F# 如何定义F中自定义计算操作的收益率和#
我正在为我的应用程序开发一些DSL,下面是我如何定义计算类型和生成器的:F# 如何定义F中自定义计算操作的收益率和#,f#,computation-expression,F#,Computation Expression,我正在为我的应用程序开发一些DSL,下面是我如何定义计算类型和生成器的: // expression type type Action<'a,'b> = Action of ('a -> Async<'b>) let runAction (Action r) ctx = r ctx let returnF a = Action (fun _ -> async {return a}) let bind m f = Action (fun r -> asy
// expression type
type Action<'a,'b> = Action of ('a -> Async<'b>)
let runAction (Action r) ctx = r ctx
let returnF a = Action (fun _ -> async {return a})
let bind m f = Action (fun r -> async {
let! a = runAction m r in return! runAction (f a) r
})
let bindA ac f = Action (fun r -> async {
let! a = ac in return! runAction (f a) r
})
type ActionBuilder<'x>() =
member this.Return(c) = returnF c
member this.Zero() = returnF ()
member this.Delay(f) = bind (returnF ()) f
// binds both monadic and for async computations
member this.Bind(m, f) = bind m f
member this.Bind(m, f) = bindA m f
member this.Combine(r1, r2) = bind r1 (fun () -> r2)
member this.For(s:seq<_>, f) = Action (fun x -> async {
for i in s do runAction (f i) x |> ignore
})
// here's the attempt to implement 'need' operations
[<CustomOperation("need")>]
member this.Need(Action a, targets: string list) =
Action (fun x ->
let r = a x
printfn "need(%A, [%A])" a targets
r)
member this.For(a, f) = bindA a f
member this.Yield(()) =
returnF ()
let action = ActionBuilder<string>()
/////////////////////////////////////////////////////////////
// other functions for Action
/// Gets action context
let getCtx = Action (fun ctx -> async {return ctx})
let needFn res = action {
let! ctx = getCtx
printfn "need([%A]) in %A" res ctx
}
现在我想改变do!needFn[“def”;“dd”]
通过定义“need”自定义操作,将语法修改为更好的语法,但会收到编译器的各种抱怨。这是正确的方法还是我误用了计算表达式
另一个问题是,如果这样做,for将不起作用!在循环体内部使用。阅读论文后,通过尝试和错误方法,我得出了以下
实现的(Yield
builder方法不是必需的):
let forF(e:seq)prog=
使用f(e.GetEnumerator())(e->
whileF
(乐趣()->e.MoveNext())
((乐趣()->prog e.Current)|>delayF)
)
可以在中找到计算表达式生成器的完整源代码。整个项目是仿造系统的变种
注意:操作已重命名为Recipe<代码>需要
运算符根本无法实现
let program1 = fun filename -> action {
let! a = async {return 123}
let f = a+1
// need ["def"; "dd"]
do! needFn ["def"; "dd"]
printfn "after need"
for i in [0..10] do
do! Async.Sleep (1)
printfn "i: %A" i
let! d = async {return f}
let! ctx = getCtx
printfn "ctx: %A, %A" ctx f
}
Async.RunSynchronously(runAction (program1 "m.c") "abc")
let forF (e: seq<_>) prog =
usingF (e.GetEnumerator()) (fun e ->
whileF
(fun () -> e.MoveNext())
((fun () -> prog e.Current) |> delayF)
)