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

Tim*_*son 13 f#

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

Tom*_*cek 7

除了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)

因此,它可以做你想要的东西,但它不能在当前版本中做(我相信其中一个原因是,这增加了太多的包装,其伤害的性能).

  • 谢谢 - 我一定在考虑早期测试版的工作方式.在哪种情况下,`Combine`方法的目的是什么?它的签名`(a:M <unit>,b:M <T>) - > M <T>`表明它的目的是_'do`a`然后做'b`'_. (3认同)

Dar*_*rio 5

不,因为那是常规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任何地方定期.