次のような型シグネチャを持つ関数を使用して、プロジェクトにデバッグ印刷を追加したいと考えています。
bool -> Printf.TextWriterFormat<'a> -> 'a
つまり、冗長モードかどうかを示す bool を受け取り、それを使用して印刷するかどうかを決定する必要があります。
たとえば、次のdprint : bool -> Printf.TextWriterFormat<'a> -> 'a
動作が必要だとしましょう。
> dprint true "Hello I'm %d" 52;;
Hello I'm 52
val it : unit = ()
> dprint false "Hello I'm %d" 52;;
val it : unit = ()
これは、コマンド ライン フラグを使用して、この出力の制御を回避できるという考え方です。また、「冗長ではない」場合のランタイム コストも避けたいと考えています。を使用して、このように機能する関数を定義することができますkprintf
。
let dprint (v: bool) (fmt: Printf.StringFormat<'a,unit>) =
let printVerbose (s: string) =
if v then System.Console.WriteLine(s)
fmt |> Printf.kprintf printVerbose
しかし、(b \in {true,false}) を使用して一連の数字を印刷/無視するとList.iter (dprint b "%A") [1..10000]
、私のマシンでは b の両方の値に対して 1.5 秒かかります。
リフレクションを使用して、適切に型指定された関数を構築し、書式設定引数を破棄する別の方法を思いつきました。
let dprint (v: bool) (fmt: Printf.TextWriterFormat<'a>) : 'a =
let rec mkKn (ty: System.Type) =
if FSharpType.IsFunction(ty) then
let _, ran = FSharpType.GetFunctionElements(ty)
FSharpValue.MakeFunction(ty,(fun _ -> mkKn ran))
else
box ()
if v then
printfn fmt
else
unbox<'a> (mkKn typeof<'a>)
しかし、ここではリフレクションが高すぎるようです (標準ライブラリの複雑な定義内で行われる場合よりもさらに高くなりますprintf
)。
コードに次のようなものを散らかしたくありません。
if !Options.verbose then
printfn "Debug important value: %A" bigObject5
または閉鎖:
dprint (fun () -> printfn "Debug important value: %A" bigObject5)
それで、他の解決策はありますか?