最近体验了一下 Facebook 推的 ReasonML 说说我的感想(其实也不是最近,只是最近整理东西的时候翻到了以前尝试的时候留下的代码,就整理了一下然后发出来
ReasonML 是基于 BuckleScript 的,而后者又是基于 OCaml 实现的编译到 JavaScript 的语言。Facebook 还推出了 ReasonReact,似乎是作为 cutting-edge 的 react 存在,这里我们先无视掉。
语法部分就不多说了,官网都有介绍,熟悉 OCaml语法的人甚至可以不用看。
我这里直接以用他实现的 toy lib 说一说和 JavaScript 密切相关的部分
https://github.com/Shuumatsu/promise-channel
(这只是作为一个初体验的报告,并没有深层次的内容,或许我使用的时候也搞错了什么,但是真的没办法,文档真的太烂了...
(下面用到的代码部分是伪代码
首先是 Promise,BuckleScript 提供了一个 Promise 的 binding, https://bucklescript.github.io/bucklescript/api/Js.Promise.html
在 ReasonML 中 chain promise 类似于 monad
Js.Promise.resolve (transformer item) |> Js.Promise.then_ (fun transformed -> ...)
感觉类似于return (transformer item) >>= \transformed -> ...
这里 transformer 是一个一般的函数,但是实际上转译出来的 JavaScript 代码 transformer 可以是一个返回 promise 的函数,比如 const transformer = x => Promise.resolve(x+1). 如果 transformer 是这种实现,Js.Promise.then_ (fun transformed -> ...) 中的 transformed 的类型会是 'a Js.Promise.t, 而其实对 JavaScript 来说类型还是 'a(比如 Promise.resolve(Promise.resolve(1)).then(console.log) 会打印 1 而不是打印 promise
这就导致了同一份代码,在 JavaScript 和 ReasonML 侧调用的时候会有完全不同行为。
和 Golang 中的 channel 不同,我尝试给我的 channel 添加一个可选的 transform 的功能
chan := make(string to int)
chan <- "1"
x := <- chan
// x will be 1
所以现在就有了两种 channel,带 transform 的和不带的。内部实现的时候如果我使用同一个函数去处理 put 操作,那这个 string to int 的 transformer 因为类型系统就不合法,只能是 int to int
(仅仅是多一步 transformer? transformer(item) : item 我实在是不想把这两种 channel 区别对待
然后是 Iterator 部分
为了模拟 Golang 中的 for range 语法,我需要实现 Iterator Protocol。
for await (const item of chan) {
if (item === 5) {
break
}
console.log(item)
}
但是 Facebook 的官方文档完全没有提到这方面相关的内容,而且没有提供 Symbol 的绑定。
而且似乎在 ReasonML 中根本不能实现 generator function(虽然我也没有用 generator hhh..)。
最后我选择在 JavaScript 文件中实现 Iterator Protocol
总的来说 ReasonML 还是处于非常早期的阶段,文档非常少,并且依赖 OCaml 的相关知识(虽然官方的说辞是不需要,但是一上来就是 ocaml attributes,我觉得还是很容易一头雾水的。
不支持 async/await,只能使用 promise,官方的说辞是暂时没有,怎么实现还没定,反正会有的。
调用 JavaScript 代码部分的设计感觉是很好的处理了 JavaScript 类型系统和 OCaml 类型系统的矛盾,但是写起来还是很麻烦,估计还是需要官方提供大量的 binding。
然后是用 OCaml 的库的问题,貌似是可以的,而且似乎 ReasonML 也能够无缝的在 dune 项目中使用,但是文档中着墨实在太少,这次我尝试写的 toy lib 也用不到,就没管了。