8

我正在寻找学习 F#,但让我感到困惑的一件事是计算表达式(do-notation??)语法和脱糖。

在 haskell 中,您有一个非常简单的 Monad 类型类和将 do-notation 脱糖到 bind 和 return 的规则。添加关键字没有魔法。唯一必须匹配的是类型。

在 F# 中有一堆构建器、关键字和复杂性。

关于如何将一个概念映射到另一个概念是否有很好的解释?

我基本上想知道我如何映射

do
  x <- monadicComputation
  foo x
  someOtherMonadicComputation
  let y = somePureComputation x
  return $ bar y

到F#。

haskell 中唯一的关键字是 do、(<-) 和 let。

4

3 回答 3

15

您不能在 F# 中编写通用 monad 代码,而是必须通过命名与表达式关联的构建器来指定您正在使用的 monad。您的示例代码如下所示:

let example = async {
    let! a = someAsyncComputation
    foo a
    do! someOtherAsyncComputation
    let y = somePureComputation a
    return (bar y)
}

对于async计算表达式类型。'bang' 模式(do!、let! 等)用于绑定 monadic 值,而常规关键字用于非 monadic 值。

let!对应于绑定(>>=),而let对应letdo符号。return对应于return, whilereturn!用于产生现有的一元值。do!类似于(>>)which 为它的效果执行一个单子值,而dois 用于非单子效果,这在 Haskell 中没有并行。

于 2013-10-25T12:15:43.160 回答
5

如果你有 Haskell 背景,那么你可能会对我最近写的一篇关于 F# 计算表达式的学术文章感兴趣。

它将计算表达式语法(非常灵活)链接到 Haskell 中使用的标准类型类。如前所述,F# 不容易让您在 monad 上编写泛型代码(可以这样做,但不是惯用的),但另一方面,它可以让您选择最合适的语法,您甚至可以获得很好的语法 for MonadPlusor用于单子变压器。

除了asyncLee 提到的 monad 之外,这里还有一个示例MonadPlus(使用序列表达式 - 列表 monad - 作为示例):

let duplicate list = seq { 
  for n in list do 
    yield n 
    yield n ∗ 10 }

或者解析器的计算表达式:

let rec zeroOrMore p = parse {
  return! oneOrMore p 
  return [] }
于 2013-10-25T15:04:11.800 回答
4

haskell do 表示法只有一种特殊的语法,即<-映射到bind函数,do 中的所有其他内容只是普通函数应用程序,其结果是 monad 类型,例如:returnputStr

同样,在 F# 中,您必须let!表示bind操作和return关键字语法糖(不像在 haskell 中那样正常调用函数,但此关键字映射到Return您定义的函数)。现在您的计算表达式可以支持许多其他关键字(如果不需要,您可以轻松省略它们),它们都记录在这里。这些额外的操作为您提供了使用 F# 关键字而不是返回一元值的普通函数的语法糖。您可以看到,您可以在 F# 计算表达式中重载的所有关键字都具有一元返回值。

因此,基本上,您无需担心所有这些关键字,只需将它们视为普通的 monad 返回函数(具有可以在文档中找到的特定类型签名),您可以在计算表达式语法中使用 F# 关键字调用它们.

于 2013-10-25T10:22:01.327 回答