Haskell程序员的计算表达式

时间:2013-10-25 10:03:31

标签: haskell f# monads computation-expression

我正在学习F#,但有一点令我感到困惑的是计算表达式(do-notation ??)语法和desugaring。

在haskell中,你有一个非常简单的Monad类型类和desugaring do-notation到bind和return的规则。添加关键字没有任何魔力;唯一必须匹配的是类型。

在F#中,有许多构建器,关键字和复杂性。

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

我基本上想知道如何映射

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

到F#。

haskell中唯一的关键字是do,(&lt ;-)和let。

3 个答案:

答案 0 :(得分:14)

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

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

表示async计算表达式类型。绑定monadic值时使用'bang'模式(do!,let!etc.),而常规关键字用于非monadic值。

let!对应绑定(>>=),而let对应let表示法中的doreturn对应return,而return!用于产生现有的monadic值。 do!类似于(>>)执行其效果的monadic值,而do用于非monadic效果,在Haskell中没有并行。

答案 1 :(得分:4)

如果你来自Haskell背景,那么你最近对我写的关于F#计算表达式的an academic article感兴趣。

它将计算表达式语法(非常灵活)链接到Haskell中使用的标准类型类。正如已经提到的,F#不容易让你在monad上编写泛型代码(可以完成,但它不是惯用的),但另一方面它允许你选择最合适的语法和你甚至可以为MonadPlus或monad变换器获得良好的语法。

除了Lee提到的async 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 [] }

答案 2 :(得分:3)

haskell符号只有一个特殊语法,即<-映射到bind函数,其他内容do只是普通函数应用程序,其结果是monad类型,例如: returnputStr等。

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

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