如何可选地提供 OCaml (let*) 运算符以与新旧编译器一起使用?

Posted

技术标签:

【中文标题】如何可选地提供 OCaml (let*) 运算符以与新旧编译器一起使用?【英文标题】:How to provide an OCaml (let*) operator optionally, to work with old and new compilers? 【发布时间】:2021-05-21 04:55:40 【问题描述】:

我有一个模块MyMonad,它提供绑定函数作为(let*) 运算符,但也作为>>= 运算符用于旧式代码。

这个想法是旧代码可以将其用作:

let foobar () =
  let open MyMonad in
  foo "test" >>= fun s ->
  bar s 1 >>= fun (a, b) ->
  return a + b

在 OCaml >= 4.08 上编译的新代码可以将其用作:

let foobar () =
  let open MyMonad in
  let* s = foo "test" in
  let* a, b = bar s 1 in
  return a + b

在模块MyMonad.ml 中,这些运算符以直接的方式实现:

let (>>=) a f =
  ...

let (let*) = (>>=)

但是,在 OCaml MyMonad.mli 接口文件中的val (let*) : ... 行也是如此。

这个问题特别是当这个模块也打算用于 BuckleScript(现在的 ReScript)时,它基于 OCaml 4.06,并且不清楚他们何时会升级到更高的 OCaml 版本。

如何将最后几行标记为仅在 OCaml >= 4.08 上编译?

注意: 我知道我可以创建两个模块,一个在另一个之上添加 (let*),并且在旧编译器中被排除在外。但我想知道是否有更优雅的解决方案。

【问题讨论】:

【参考方案1】:

语言或 stdlib 的许多新增内容之后是通常称为 *-shims 的反向移植库。

对于你的问题,有

https://github.com/ocaml-ppx/ocaml-syntax-shims

【讨论】:

感谢您的回答,这表明我需要进一步澄清我的问题。据我所知,那些 ocaml-syntax-shims 或一般的 ocaml-ppx 不适用于 BuckleScript/ReScript,是吗? @vog 不幸的是,我不知道带扣/rescript 是怎么回事。如果我没记错的话,let 运算符的“未来语法”仅适用于沙丘项目。我可能弄错了;带上一粒盐。 @vog 我认为 ReScript 团队出于所有意图和目的构建了一种完全独立的语言,恰好使用旧版本的 OCaml 编译器。所以我怀疑他们是否会包含他们没有明确提及的任何 OCaml 功能,包括 ppxes 和 (let*) 语法。 @kevinji 幸运的是,这不是真的。 (但如果他们严格地走这条路,他们很快就会对我们变得毫无用处,而且我认为我们不是独一无二的,我认为他们会失去他们社区的重要组成部分。)我注意到他们自己的构建系统配置,bsconfig,确实为pp等提供了手段,一旦一切正常运行,我就会写下我的问题的答案。 @kevinji 我刚刚添加了我的发现作为第二个答案。【参考方案2】:

要自己回答这个问题,确实需要坚持>>=,新语法可以通过shims与旧的OCaml编译器甚至BuckleScript(现在的ReScript)一起使用。

后者可以如下实现:

    在当前目录中为 4.06 OCaml 编译器创建一个新的 OPAM 开关。这是当前 BuckleScript 版本所基于的版本,需要说服 shims 实际执行某些操作(对于最新的编译器版本,它们将编译为无操作):

    opam switch create -wy --no-install . 4.06.0
    

    安装ocaml-syntax-shims OPAM 包:

    opam install -wy ocaml-syntax-shims
    

    bsconfig.json配置文件中添加如下预处理行:

    
      "pp-flags": "./_opam/bin/ocaml-syntax-shims -dump-ast",
      ...
    
    

【讨论】:

以上是关于如何可选地提供 OCaml (let*) 运算符以与新旧编译器一起使用?的主要内容,如果未能解决你的问题,请参考以下文章

可选地提供静态压缩的CSS&JS

OCaml - 如何在匹配表达式中放置一个 let 绑定?

在 OCaml 中分隔多个“let”声明,后跟一个“let in”表达式

parsley.js 可选地验证数字输入

如何卸载 CSV 文件,其中只有非空值用引号括起来,引号可选地包含在内,并且空值不被引用?

“let () =”在 Ocaml 中是啥意思?