最近体验了一下 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 也用不到,就没管了。