Reason ML + bucklescript で最高の React アプリ開発体験を目指すぞ!

これは Reason ML Advent Calendar の1日目です。時を遡って1日目です。思い立ったんでカレンダーごと作りました。

注意点として、基本的に、多少コンパイラとかメタプロが好きな程度のJSプログラマとしての視点で書いています。 ocaml ユーザーではありませんので、間違いがあったら編集リクエストやコメント欄などでご指摘ください。

Reason

Facebook の chenglou 氏が作ってる ocaml の言語拡張で、1方言という位置づけです。chenglou氏は react-motion の人というと React界隈では通りがいいと思います。

Reason の一番の特色は ocaml に js っぽいフレーバーの構文にしつつ、React.js の JSX 構文に対応していて、 BuckleScript をバックエンドしながら JS を生成して、 React アプリを簡単に作れるような言語を目指してる、という感じです。勿論、ocaml なので、ネイティブコードを吐くことを出来ます。

Examples

コードは公式ガイドから。

https://reasonml.github.io/guide/javascript/syntax-cheatsheet

宣言

let myInt = 5;
let myInt: int = 5;
let myInt = (5: int) + (4: int);
let add = (x: int, y: int) : int => x + y;
let drawCircle = (~radius as r: int) : unit => ...;

ocaml なので標準で immutable です。

Mutable

let x = ref(0)
x := 1
Js.log(x^)

関数

let myFun = (x, y) => {
  let doubleX = x + x;
  let doubleY = y + y;
  doubleX + doubleY
};

ブロック末尾でセミコロンを省略するとその値が return されます。この辺は rust とも通じる感じ。

型とデストラクチャリング

type person = {name: string, age: int};
let somePerson = {name: "Guy", age: 30};
let {name, age} = somePerson;

これ、 flowtype ならそのまま評価できるコードですね。

パターンマッチ


let optionBoolToJsBoolean = (opt) =>
  switch opt {
  | None => Js.false_
  | Some(true) => Js.true_
  | Some(false) => Js.false_
  };

JSの哀れで貧弱な switch と違い本物のパターンマッチがあります。

JSX

components/app.re
let component = ReasonReact.statelessComponent("App");

let handleClick = (_event, _self) => Js.log("clicked!");

let make = (~message, _children) => {
  ...component,
  render: (self) =>
    <div onClick=(self.handle(handleClick))>
      (ReasonReact.stringToElement(message))
    </div>
};

Reactちょっと癖がありますね…。

個人的な感想ですが、Babel + flow とすごく書き味が似ています。というか flow はこれを目指しているんだと思います。 flow の人も元 ActionScript コンパイラの ML畑の人ですし。

Facebook(というかchenglou氏)の思惑を邪推すると、 とにかく JS フレンドリーにして flow で型システムに馴らしたユーザーを Reason に呼び込みたいんだと思います。

Quick start

始めるだけならすごく簡単です。ocaml/opam 環境を作る必要はありません。

npm install -g bs-platform
bsb -init my-first-app -theme basic-reason

とはいえ、 bs-platform(backlescript) のインストールで、backlescript のバイナリ落とすんですけどね。

とりあえず、さっくりReactのSPAを動かせるボイラープレート作りました。

https://github.com/mizchi-sandbox/simple-reason-boilerplate

これを clone して yarn install; yarn watch; して localhost:4000 で動くはず。 react と jest で動いてます。

BuckleScript

https://github.com/BuckleScript/bucklescript

BuckleScript は ocaml の中間表現から javascript を生成するコンパイラです。いわゆる altjs。
BuckleScript がすごいのは、commonjs として比較的可読性が高い、 commonjs を生成してくれます。

ocaml を全く知らなくても書けますか?

NO、だけど必要なものを覚えるだけなら、触り程度で大丈夫。

糖衣構文なので、構文サポート外の挙動はすぐに ocaml の標準関数などを使う必要があります。また、型が厳密なので、JSオブジェクトの生成に型合わせゲームも発生します。そのコード。

let jsonArray =
  [true, false, true]
  |> List.map(Js.Boolean.to_js_boolean)
  |> Array.of_list
  |> Js.Json.booleanArray;
Js.log(jsonArray)

(パイピングオペレータ便利ですね… ES stage-2 なんでそのうちJSにも入るんですが)

この「糖衣構文だけどすぐにバックエンドがむき出しになる」という書き味は、Elixir を書く時にOTP出てきたのと同じ雰囲気があります。

とはいえ、JS 目線だと、組み込み関数があまりにも何もない言語なので、それに比べると多少覚え直しが必要とは言え、前に進んでる感だけあります。

便利ツール

refmt

標準でついてくるフォーマッタです。最近の言語はフォーマッタが標準搭載ですね。そのうちAST直接書くようになりそう。(手書き wat…)
全然関係ないですが JavaScript 書く人は全員 prettier を使ったほうがいいと思います。

rtop

いわゆる REPL。bucklescript ではなくネイティブ環境なのに注意。

開発環境

自分の環境

  • Atom(AtomIDE)
  • ide-reason

Reason MLに対する個人的な期待

ちょっとフロントエンドの話をします。

外からどう見えているか知りませんが、フロントエンド激動の時代は一段落つき、目指すべきゴールが見えて、あとは各種エコシステムの進化を待つ、という状態だと思っています。yak shaving は続きますが、残す大きな進化は、型システムの導入如何と wasm ぐらいでしょうか。

ライブラリも、今は一旦 React/Angular/Vue という対立構造は残っているものの、三者三様の役割があり、これらが Web Components に対応していくという流れで、その中で新しいものが出るかもね、ぐらいの温度感です。三者ともレンダラ最適化はありますがデータモデリング層はRedux/Rx/Vuex(?) と固まりつつあります。

というわけで、時間が必要で、新しいもの好きな自分としては、飽きて次のステージに進みたい、という時期です。(今フリーランスなんで仕事量は調節できて、時間もあるので…)

JSは型システムが貧弱ですが、今のJSはJITに向けた最適化はシェープの確定、それを開発環境で上手く認識するには型推論が必要、という歪な状態です。また、Rx や Reducer というパラダイムでは、静的な型指定はほぼ必須です。

なので、型システムこそ最後に残されたフロンティアで、TS/Flow がその最前線ですが、正直もう3年ぐらい使ってると、マンネリ感や、JSとしての限界もあり感じています。

あと単に前から ml やるきっかけが欲しかったのでその理由を上のようにこじつけてます。

Reason は React ぐらい流行るか?

なんとも言えません。そもそも日本で ML ユーザーが少なすぎます。MLやるようなCSの人がフロントエンドやらないというのもありますが。

chenglou 氏の公演動画見ても 「MLで最高の生産性を得られるのは自明」みたいなことを言っていて、そこが伝わらないので、訴求しようすると、そもそも認知の限界がありそう、みたいな感じがしています。そもそも自分が言及するまでアドベントカレンダーなかったし…

言語の見た目を多少JSに近づける構文から入ったのは、アプローチとしては正解だと思います。JSユーザーは新しい型システムと新しい構文を持ってocamlの組み込み関数を多少使える、みたいな目線から入るほうが、マーケティング的にはいいんじゃないですか。

勿論、現段階で仕事で使うにはちょっと攻めすぎてますが、ocaml 使える人が多いチームで、ライブラリより自前で書くほうが多いなら選択肢になりえます。

Node.jsエンジニアという目線だと、 BuckleScriptは最高で、自分が知ってるcommonjsのインターフェースを提供してくれるもので、色んなライブラリの一部を 段階的に Reason に置き換えると言ったアプローチがとれます。

まとめ

  • ML が JS風味 で React アプリが書ける
  • ocaml エンジニアが最高の生産性を出せる環境だが、新しいフロントエンド開発言語として認識するのもアリ
  • 流行ったら自分が嬉しい

気になった人はこの期に調べてみて、記事を書いてみてください。