是否可以组合一个计算表达式构建器,它可以对两个或多个表达式进行排序,而不会将do!
放在每个表达式的前面?
如果我已正确阅读relevant section of the manual,则应通过构建器的Combine
方法实现。但是,似乎没有使用我的Combine
方法;相反,我得到一个编译器警告,建议我使用ignore
来丢弃结果。
例如,给定F# State 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#"]
答案 0 :(得分:7)
除了Dario所写的内容之外,您无法重新定义通常的排序以表现为monadic do!
(即使您决定不在计算中支持非monadic操作)。问题在于翻译器不会以任何特殊方式处理通常的排序,因此没有可以使用的截取点。您的示例将如下翻译:
let m = state.Delay(fun () ->
hello "world"
hello "F#"
state.Zero())
对hello
的调用未包含在可重新定义的任何成员调用中。
在F#排序的早期版本中,过去常常被转换为对此Let
成员的调用:
let m = state.Delay(fun () ->
state.Let(hello "world", fun _ ->
state.Let(hello "F#", fun _ ->
state.Zero())))
所以它可能可以做你想要的,但它不能在当前版本中完成(我相信一个原因是这增加了太多的包装,这会损害性能)。
答案 1 :(得分:5)
不,因为这是常规do
的用途。如果你想要monadic do,即do!
,你必须明确。 示例:强>
let m = state {
printfn "World"
hello "World"
return 42
}
printfn
表达式的类型为unit
,并且隐含do printfn
。hello
案件中?我们需要monadic绑定!现在编译器如何知道选择什么,do
或do!
?也许按类型(Scala这样做),但是现在,它没有。所以它只是在任何地方假定do
。