省略'做!'在计算表达式中

时间:2011-01-03 19:11:47

标签: f#

是否可以组合一个计算表达式构建器,它可以对两个或多个表达式进行排序,而不会将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#"]

2 个答案:

答案 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绑定!

现在编译器如何知道选择什么,dodo!?也许按类型(Scala这样做),但是现在,它没有。所以它只是在任何地方假定do