facebook の Reason という言語を調べていた

また facebook 製の名前空間を考慮しないシリーズが増えていた。半年ぐらい前から存在は知られていたリポジトリだけど、最近ドキュメントが新しく、わかりやすくなっていた。https://facebook.github.io/reason/

## Reason

https://github.com/facebook/reason

- Approachable syntax.
- Powerful, automatic source code formatting.
- Adopt incrementally with JavaScript/C interop.
- Ahead-of-time compilation to assembly - without a language level VM.
- Rapidly develop and share projects.

> Why OCaml?OCaml is a great tool for writing highly expressive, functional or imperative code, with type inference and fast runtime performance. Because of these properties, OCaml has helped Facebook quickly build scalable infrastructure such as Hack, Flow, and Infer. It is also used for other performance sensitive applications in the financial industry (Jane Street, Bloomberg). At the same time, OCaml has a very mature (and still growing) ecosystem for targeting browser and JavaScript environments with a focus on language interoperability and integration with existing JavaScript code.

https://facebook.github.io/reason/

要はOCamlの構文拡張フロントエンド。

## 個人的な興味の話

FacebookはFlowtypeでJS環境の知見あるし、BuckleScript (Bloomberg製 OCaml => JSコンパイラ) と組み合わせるのが簡単、というのをみて、いわゆるAltJSとしてどのぐらい使えるか、検証してみよう、というのが個人的な動機。

かつ構文がJSに多少寄ってるので、自分の学習コスト的な意味でもさっくり学んでおくのにちょうどよいのでは？という期待もあった。

## Install

https://github.com/facebook/reason#installing-via-opam に従って入れた。

```
# On OSX, install opam via Homebrew:
brew update
brew install opam
# On Linux, see here (you will need opam >= 1.2.2): http://opam.ocaml.org/doc/Install.html

opam init
# Add this to your ~/.bashrc (or ~/.zshrc):
#   eval $(opam config env)

opam update
opam switch 4.02.3
eval $(opam config env)
opam install reason
```


## 構文

https://facebook.github.io/reason/ を眺めてください。普通の OCaml が JS っぽい拡張を施されています。

インストールしたら rtop で REPL が叩けるんで、そこで

## JSビルドの作成

https://github.com/mizchi-sandbox/reason-js-sandbox という場所でいろいろ試していた。参考にしたのは https://github.com/chenglou/intro-to-reason-compilation/tree/master/step7 

こんなコードあるとして

```ml:src/myMod.re
let secret = "hello";

let increment = fun (x) => x + 1;

let three = {
  let one = 1;
  let two = 2;
  one + two
};
```

これをJSをから呼んでテストを書いてみる

```js:test/js/myMod.test.js
const test = require('ava')
const myMod = require('../../_build/self/myMod')

test('same output with reason', t => {
  t.is(myMod.secret, 'hello')
})

test('increment', t => {
  t.is(myMod.increment(3), 4)
})

test('three', t => {
  t.is(myMod.three, 3)
})
```

これは reason もだけど bucklescript の吐き出してくれるJSをが自然でよいですね。

ビルドスクリプトはこう。

```sh:build.sh
#!/usr/bin/env sh
rm -rf _build
mkdir -p _build/reason-js
node_modules/bs-platform/bin/bsc.exe -g -bin-annot -pp "refmt --print binary" -bs-package-name self \
  -bs-package-output commonjs:_build/reason-js -o _build/reason-js/ReasonJs \
  -c -impl node_modules/reason-js/src/ReasonJs.re
mkdir -p _build/self
selfSortedFiles=$(ocamldep -ppx ./node_modules/bs-platform/bin/bsppx.exe -pp "refmt --print binary" -sort -ml-synonym .re src/*.re)

for source in $selfSortedFiles
do
  destination=$(echo $source | sed "s/src/_build\/self/" | sed "s/\.re$//")
  node_modules/bs-platform/bin/bsc.exe -g -bin-annot -pp "refmt --print binary" -bs-package-name self \
    -bs-package-output commonjs:_build/self -I _build/self -I _build/reason-js \
    -o $destination -c -impl $source
done
```

長いけどすんなり動いたので、そんなに警戒感はない。

## エコシステム

が、よくわからない。node_modules や npmを使ってるように見えるのだが、単なるソース置き場として相乗りしてるだけのようにも見える。

https://github.com/reasonml を眺めていると、 https://github.com/reasonml/esy という yarn のフォークがあり、何を使えばいいのか、よくわからない。

Discord グループあったんで、入って質問投げたところ。

## 感想

flowtypeからの延長線という視点で、MLが多少JS風になる言語を提供するのは自然だと思う。とはいえ、まったく枯れてないし、ついていくのはJSの視点じゃなくてML的腕力が必要だと思う。

↑のコードは、非常にわかりやすいけど、JSの関数を呼ぼうとするとこんなコードになる。

```
/* values that can potentially be null are type checked correctly! */
Random.self_init ();
let msg =
  Random.int 2 === 0 ? Js.null : Js.Null.return "This message might not display.";

switch (Js.Null.to_opt msg) {
| None => ()
| Some msg => print_endline msg
};

/* let's try some BuckleScript-JavaScript interop */
ReasonJs.setTimeout (fun () => print_endline "Here's a message after a 1 second timeout.") 1000;
```

BuckleScript のマクロも覚えないといけないし、付け焼き刃だと死んでしまうので、もうちょっとML理解してから触るのがよさそう。

だれかML強い人触ってみてください。


## 追記

Discord で教えてもらったけど https://bloomberg.github.io/bucklescript/Manual.html#_integration_with_reason ということでインテグレーションがあり、 https://github.com/mizchi-sandbox/try-bsb-with-reason で `npm run bsb -w` と叩くだけで `.merlin` (たぶんエディタ補完のヒントをつくってくれるやつ)も生成してくれて、最初に貼ったディレクトリのやつは内部を理解するにはいいけど、とくに頑張る必要はなかった。