如何可选地提供 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*) 运算符以与新旧编译器一起使用?的主要内容,如果未能解决你的问题,请参考以下文章
在 OCaml 中分隔多个“let”声明,后跟一个“let in”表达式