是否可以组合一个计算表达式构建器,它可以对两个或多个表达式进行排序而不必放在do!
每个表达式的前面?
如果我已正确阅读本手册的相关部分,则应通过构建器的Combine
方法实现.但是,我的Combine
方法似乎没有被使用; 相反,我得到一个编译器警告,建议我用它ignore
来丢弃结果.
例如,给定一个F#状态monad,我希望能够这样做:
let hello who = State (fun lines -> lines @ [sprintf "hello %s" who])
let m = state {
hello "world"
hello "F#"
}
let l = Execute m []
// l should now contain ["hello world"; "hello F#"]
Run Code Online (Sandbox Code Playgroud)
除了Dario所写的内容之外,您无法重新定义通常的序列以表现为monadic do!
(即使您决定不在计算中支持非monadic操作).问题在于翻译器不会以任何特殊方式处理通常的排序,因此没有可以使用的截取点.您的示例将被翻译为:
let m = state.Delay(fun () ->
hello "world"
hello "F#"
state.Zero())
Run Code Online (Sandbox Code Playgroud)
调用hello
不会包含在可以重新定义的任何成员调用中.
在早期版本的F#中,测序用于转换为Let
对此成员的调用,如下所示:
let m = state.Delay(fun () ->
state.Let(hello "world", fun _ ->
state.Let(hello "F#", fun _ ->
state.Zero())))
Run Code Online (Sandbox Code Playgroud)
因此,它是可以做你想要的东西,但它不能在当前版本中做(我相信其中一个原因是,这增加了太多的包装,其伤害的性能).
不,因为那是常规do
的.如果你想要monadic do,即do!
你必须明确.例:
let m = state {
printfn "World"
hello "World"
return 42
}
Run Code Online (Sandbox Code Playgroud)
printfn
表达式的类型的unit
,并且有一个do printfn
隐式的.hello
情况下?我们需要monadic绑定!现在编译器如何知道要选择什么,do
或者do!
?也许按类型(Scala这样做),但是现在,它没有.所以它只是在do
任何地方定期.