LoginSignup
13

More than 3 years have passed since last update.

知らない言語を使ってみたい - ReasonML編 (OCaml な AltJS)

Last updated at Posted at 2018-12-08

どこか遠くへ行きたい

今日は少し節約です。『知らない言語』じゃないので、看板に偽りあります。
既に 1 年前に調べ尽くしているので、今回は前回からの変更点のみをまとめました。
最近、ブラウザ拡張をひとつ ReasonML で書いているので、改めて変更点まとめておきたかったのもあります。

前回の記事 : Reason 使った感想 on Windows

ReasonML

公式サイト : https://reasonml.github.io/
公式ドキュメント : https://reasonml.github.io/docs/en/what-and-why
API ドキュメント : https://reasonml.github.io/api/index
リポジトリ : https://github.com/facebook/reason

Reason lets you write simple, fast and quality type safe code while leveraging both the JavaScript & OCaml ecosystems.

用途 一応汎用だが、 Web 志向
開始 2016/02
最新バージョン 3.0.4 ( 2017/12/9 )
ライセンス MIT
プラットフォーム JavaScript
静的型付け
パッケージ管理 npm
GitHubスター 6902 ( 2018/12/02 )
  • AltJS
    • 高速なコンパイル
      • BuckleScript が Reason / OCaml コードを JavasScript にコンパイルする
    • リーダブルな JavaScript の生成
  • OCaml の Alternate Syntax
    • OCaml の強力な型システム
    • 関数型の恩恵

OCaml をベースに JSer にも親和性の高い Syntax が加えられた新しい言語みたいなイメージ。

インストール

  • Windows 10 Pro 1803
$ npm install -g bs-platform

これだけで導入は完了。Windows でも問題なし。素晴らしい。

エディタ支援

Editor Plugins - Reason

VS Code が推奨されているので、素直にそれを使う。

これまでは、以下のプラグインを利用していたが、
https://marketplace.visualstudio.com/items?itemName=freebroccolo.reasonml

今後は公式に作られている以下プラグインの方が良いだろう。
https://marketplace.visualstudio.com/items?itemName=jaredly.reason-vscode

サンプル体験

コードの書き心地をするだけなら、Playground が用意されているが、実際の開発をイメージするためにローカルで始める。

プロジェクト作成

$ bsb -init sample_1206 -theme basic-reason

$ cd sample_1206
$ tree
# .
# ├── bsconfig.json
# ├── node_modules
# │  └── bs-platform -> /mnt/c/Users/username/scoop/persist/nodejs/bin/node_modules/bs-platform
# ├── package.json
# ├── README.md
# └── src
#    └── Demo.re

コード

ちょっとコードを変更してみる。

let fizzbuzz = (i) =>
  switch (i mod 3, i mod 5) {
    | (0, 0) => "FizzBuzz"
    | (0, _) => "Fizz"
    | (_, 0) => "Buzz"
    | _    => string_of_int(i)
  }

for (i in 1 to 100) {
  print_endline(fizzbuzz(i));
}

コンパイル

で、コンパイルすると、

$ npm run build

src/Demo.bs.js が生成される。

src/Demo.bs.js
// Generated by BUCKLESCRIPT VERSION 4.0.7, PLEASE EDIT WITH CARE
'use strict';


function fizzbuzz(i) {
  var match = i % 3;
  var match$1 = i % 5;
  if (match !== 0) {
    if (match$1 !== 0) {
      return String(i);
    } else {
      return "Buzz";
    }
  } else if (match$1 !== 0) {
    return "Fizz";
  } else {
    return "FizzBuzz";
  }
}

for(var i = 1; i <= 100; ++i){
  console.log(fizzbuzz(i));
}

exports.fizzbuzz = fizzbuzz;
/*  Not a pure module */

ちなみに、package.json は、

package.json
{
  "name": "sample_1206",
  "version": "0.1.0",
  "scripts": {
    "build": "bsb -make-world",
    "start": "bsb -make-world -w",
    "clean": "bsb -clean-world"
  },
  "keywords": [
    "BuckleScript"
  ],
  "author": "",
  "license": "MIT",
  "devDependencies": {
    "bs-platform": "^4.0.7"
  }
}

実行

Import も無いただの JavaScript なので、普通に Node で実行する。

$ node .\src\Demo.bs.js
# 8

基本的には、これで終わり。

もし Webpack を使うなら、 loader は使わず BuckleScript の in-source モードを使ってビルドとバンドルを分けるのが作法とのこと。Webpack と bs-platform の2つの Watcher を動かすのはちょっと面倒だけど。

Parcel を使うなら、全部解決してくれる

1 年で進歩した点

前回の記事 : Reason 使った感想 on Windows

1. 公式推奨の VS Code 拡張が作られた

過去記事 : VS Code で開発する

VS Code の拡張が新たに作られた。

https://marketplace.visualstudio.com/items?itemName=jaredly.reason-vscode
https://github.com/jaredly/reason-language-server

旧拡張 では、Windows での構築に相当手間取り、しかも最終的には上手く動かなかった。

新拡張はその点、導入もスムーズだ。特別な理由が無ければ、新拡張で良さそう。
ただ、モジュール変更 ~ 反映 までのタイムラグが結構あるのが気になる。まぁ、これは旧拡張でもあるもので、結局は WSL で BS を動かす辛さでしか無いのだが。

2. Belt という標準ライブラリ的モジュールの提供

過去記事 : 6. 標準モジュール

Reason には、元々 OCaml の標準ライブラリ ( Pervasives ) をそのまま持ってきたみたいなモジュールがデフォルトで open されていたが、もう少し Reason っぽい API の標準ライブラリ は無いものかと思っていた。

公式に Belt という標準ライブラリが提供されるようになった。
https://bucklescript.github.io/bucklescript/api/Belt.html

これは元々、便利機能を実装する予定だった BS モジュール が、名前を変えて実現したもののようだ。

例外の可能性のあるメソッド名に Exn サフィックスが付く

before
let head = try(List.hd([])) {
| Failure("hd") => 10
};
after
open Belt;
let head = try(List.headExn([])) {
| Js.Exn.Error(_) => 10
};

例外の型まで変わっているのは気になる。JavaScript 側に相当寄せてきているんだろうか。

コレクション操作関数の引数の順番が変わった

before
let odds = List.map((x) => x * 2, [1, 3, 5, 10]);
after
open Belt;
let odds = List.map([1, 3, 5, 10], (x) => x * 2);

こうなると、気になるのが |> の使い方で、あれはただ値を関数に渡しているだけだったが、位置が変わったら使えなくなる。

before
[1, 3, 5, 10]
  |> List.map((x) => x * 2)
  |> List.filter((x) => x > 7)
  |> List.iter((x) => Js.log(x))

この場合 |> は、 List.map に与えられた関数が適用されて返された List => List の関数に、[1,3,5,10] を適用しているだけだ。順番が変わると使えない。

これに対しては、新たに -> ( Fast Pipe と呼ばれる ) が追加された。
こんな感じで使える。

after
open Belt;
[1, 3, 5, 10]
  -> List.map((x) => x * 2)
  -> List.keep((x) => x > 7)
  -> List.forEach((x) => Js.log(x))

この場合、 パイプ元を第一引数に適用する。

また、|> と一緒に _ プレースポルダーを置くことで任意の位置に値を適応することも可能。

another
open Belt;
[1, 3, 5, 10]
  |> List.map(_, (x) => x * 2)
  |> List.keep(_, (x) => x > 7)
  |> List.forEach(_, (x) => Js.log(x))

この場合、関数のネストではなく、関数の演算結果が逐一変数に保存されるよな処理に置き換えられる。

よく使うデータ型の Generic Module の提供

before
module StringMap = Map.Make(String)
let m = StringMap.(
  empty
  |> add("key 1", 1)
  |> add("key 2", 2)
)
after
open Belt;
let m = Map.String.fromArray([|("key 1", 1), ("key 2", 2)|])

IntString のコレクションは提供されているようだ。

uncurried な Callback を受け取るメソッドには U サフィックスが付く

after
open Belt;

/* コンパイルエラー */
[1, 3, 5, 10]
  -> List.forEachU((x) => Js.log(x))

/* 正しくはこっち */
[1, 3, 5, 10]
  -> List.forEachU((. x) => Js.log(x))

uncurried のほうがパフォーマンスが良いらしい。
uncurry についての詳細は こちら を参照。

3. boolean の扱いが改善した

過去記事 : 8.3. 実行時セマンティクス

これまでは、Reasonml の true / false が JavaScript の 0 / 1 に変換されていたため、思いもよらない動作をすることがあった。
その為、JavaScript と bool のやり取りをする時は Js.boolean を使わなければいけなかった。

それがいつの間にか、JavaScript の bool に変換されるようになっていた。
小さいことだが、引っかかると結構なストレスだったので良かった。

4. セミコロンが強制ではなくなった

文末のセミコロンが強制ではなくなった。
未だにフォーマッタを利用すると文末にセミコロンは追加される。

思ったより進んでいなかった点

1. async/await の決着がついていない

ずーっと議論されている、async/await をどのような形で Reason に取り込むかという問題が、なかなかまとまらない。

https://github.com/facebook/reason/issues/1321
https://jaredforsyth.com/posts/building-async-await-in-reason/

2. 1年経っても Qiita のシンタックスハイライトが対応しない

まだまだ有名じゃないってことなんだろうか。
ちなみに、pony という言語の 『pony』タグは Qiita に 6 記事しか無いがシンタックスハイライトに対応している

それはさておき、どちらの言語にももっと広まってほしい。

参考

あとがき

※ この記事は個人の見解であり、所属する組織を代表するものではありません。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13