は、私は、ログや睡眠と戻り値のような副作用をもたらすことができ、計算を可能にする計算ワークフローを記述しようとしている遅延計算ワークフローを作成するには?
使用例は、この
let add x y =
compute {
do! log (sprintf "add: x = %d, y= %d" x y)
do! sleep 1000
let r = x + y
do! log (sprintf "add: result= %d" r)
return r
}
...
let result = run (add 100 1000)
と私のようなものになるだろうexecuteComputationが呼び出されたときに副作用が生成されるようにします。
私の試みは
type Effect =
| Log of string
| Sleep of int
type Computation<'t> = Computation of Lazy<'t * Effect list>
let private bind (u : 'u, effs : Effect list)
(f : 'u -> 'v * Effect list)
: ('v * Effect list) =
let v, newEffs = f u
let allEffects = List.append effs newEffs
v, allEffects
type ComputeBuilder() =
member this.Zero() = lazy ((), [])
member this.Return(x) = x, []
member this.ReturnFrom(Computation f) = f.Force()
member this.Bind(x, f) = bind x f
member this.Delay(funcToDelay) = funcToDelay
member this.Run(funcToRun) = Computation (lazy funcToRun())
let compute = new ComputeBuilder()
let log msg =(), [Log msg]
let sleep ms =(), [Sleep ms]
let run (Computation x) = x.Force()
です...しかし、コンパイラは、LET文句を言います!次のコードの行:
let x =
compute {
let! a = add 10 20
let! b = add 11 2000
return a + b
}
Error FS0001: This expression was expected to have type
'a * Effect list
but here has type
Computation<'b> (FS0001)
いずれかの提案がありますか?
F# 'async'ワークフローは、すでにあなたの' sleep'機能を与え、あなたはWriterまたは状態を使用してロギングを実装することができモナド。これにより、あなたのワークフローを 'async'のスタックとして実装し、他の2つのモナドの1つとして実装することができます。 –
私はそれを理解していますが、どのように動作するかを把握するために、最初からやりたいと思います。 – vidi
Continuation CEを調べることに興味があるかもしれません。それは怠惰なCEを実装する一つの方法です。これは基本的に 'async'の実装方法です。 – FuleSnabel