我如何阅读这段使用“~”和“:”的 OCaml 代码?

问题描述

我是 OCaml 的新手,在浏览一些代码时,我看到了以下内容

  let catch f m = M.bind m ~f:(
      function Error e -> f e
             | Ok x -
    )

据我所知,这是定义一个 try/catch 块(我的理解是 OCaml 不使用单独的 catch 块)。 M.bind 是将 m 的结果传递给第二次计算的 monadic 绑定运算符。 OCaml 参考手册说 ~ 用于标记参数,以便于理解文档中的类型签名。然而,这是否意味着第二个计算(“function ..”)也被标记为 f??

解决方法

带标签的参数与特定函数相关联。这意味着该函数有一个带有名称的参数。调用该函数时,请指定名称和值,如下所示:

 myfun ~name: value

如果此调用有效,则我们知道 myfun 具有名称为 name 的参数。

为了比较,当你调用一个没有带标签参数的函数时,调用看起来像这样:

myotherfun othervalue

接受命名参数的函数定义如下所示:

let myfun ~name =
    ... expression involving name ...

例如,这个函数从你传递的任何东西中生成一个单例列表:

let myfun ~name = [name]

在 OCaml 顶层 (REPL) 中对该函数的调用如下所示:

# myfun ~name: 44;;
- : int list = [44]

关键是这允许您在调用函数时按名称而不是按位置指定参数。您需要指定函数期望的名称。但是如果一个函数有多个命名参数,你可以按任意顺序指定它们。

这些名称仅用于 OCaml 文档是不正确的。手册告诉你的是,命名参数作为关于不同参数的用途的良好文档。对于带有大量参数的函数尤其如此,尤其是当其中一些是相同类型的函数时更是如此。使用名称可以避免以错误顺序指定名称的错误。

因此,您正在调用具有名称为 M.bind 的标记参数的函数 f。传统上,名为 f 的参数用于将函数作为参数传递,这确实是这里发生的事情。

所以;你的问题似乎是第二个参数是否被标记。 M.bind 的第二个参数被标记为是。但价值可以是任何东西。值不受传递给它的函数标签的影响。此外,您可以查看函数定义 function Error ... 并看到它没有任何带标签的参数。它只是一个接受 result 类型值的函数。

重复一遍,这是一个函数定义:

function Error -> f e | Ok x -> g x

所以我们知道关于这个函数的一切。它绝对没有任何命名参数。