ReasonMLを使う理由…ではなく入門

ReasonMLを使う理由は、まださほど使ったことないのでわかりません。

- 型がある
- null許容型が無い
- 他言語と相互運用できる

という情報は、最初に手に入りました。

githubのスター数などを見る限り、なんとなくですが海外では結構流行っているように見えます。

[TypeScriptやFlowの型定義生成もできます](https://github.com/cristianoc/genType)し、公開されているExampleの中には[GatsbyJSのサイトに組み込むような](https://github.com/draftbit/avatar-generator)部分的な利用もできたり、ライブラリの作成用途としても活躍しそうです。

公式サイトは、ところどころ未翻訳ですが、日本語記事もあります。

https://reasonml.github.io/docs/ja/what-and-why

以降も、章ごとに[【公式で見る】](https://reasonml.github.io/en/)リンクは付けておくので、ご活用ください。

自分自身も入門しながら、調べながら説明していくつもりです。

（※モジュールの項について、一部理解しきれず曖昧な記事になってます。分かり次第、更新する予定です。）

おかしいところがあったら、教えてください。

# インストール [【公式で見る】](https://reasonml.github.io/docs/en/installation)

`CLI導入` ＋ `init`の流れは公式にあるので、せっかくなのでバニラから始めてみましょう。

まずは、ディレクトリを作成し、`bs-platform`をローカルインストールします。

基本的に、みんな大好き`npm`です。

（Yarnももちろん可。開発はFacebookが始めたらしいですが、Yarn推奨というわけでもないです。）

```
mkdir reason-sample

cd reason-sample

npm init -y

npm install --save-dev bs-platform
```

これで、`bsb`コマンドが使えるようになります。

これは、**BuckleScript**（バックルスクリプト）というReasonMLをJavaScriptにコンパイルするツールです。

BuckleScriptは、

- ReasonML -> JavaScript
- OCaml -> JavaScript

という2種の変換をサポートするReasonMLの姉妹（おそらく姉）です。

ということで、

`bsb` = **B**uckle **S**cript **B**uild ツールかと。

## Hello World

`bsb`でビルドするには、`bsconfig.json`が必要です。

最低限の構成です。プロジェクトルートに作ってください。

```json
{
  "name": "reason-sample",
  "namespace": true,
  "sources": ["src"]
}
```

`name`とソース配置ディレクトリを指定するだけです。

`src`ディレクトリに`index.re`というファイルを作ります。

```bash
mkdir src
touch index.re
```

`index.re`を編集します。

```javascript
Js.log("hello world");
```

Js.logは、`console.log`にコンパイルされました。

そして、

```bash
npx bsb -make-world
```

でビルドが始まり、`lib`ディレクトリが作成されます。

`lib/js/src/index.js`がコンパイル後のJavaScriptです。

```bash
node lib/js/src/index.js
```

でHello worldは完了です。

## 【補足１】BuckleScriptについて

ここまで、ReasonMLというより、BuckleScriptのHello Worldみたいになってしまいました。

より`bsb`コマンドについて知りたい方は、こちらを参照してください。

https://bucklescript.github.io/docs/en/build-overview

`bsconfig.json`の書き方は、こちらです。

https://bucklescript.github.io/docs/en/build-configuration

あまり、翻訳は進んでないようですが、右上の「Aあ」で日本語に切り替えもできます。

翻訳に参加するのもありだと思います。

## 【補足２】開発環境

[エディタープラグイン](https://reasonml.github.io/docs/ja/editor-plugins)

⇒ 好きなIDEのものをお使いください。

[REPL環境](https://sketch.sh/)

⇒ 対話型実行環境です。

[パフォーマンス計測](https://rebench.github.io/?rebench-data=NoIg9AVABAzgFgQwE4FMAmUDGB7NKoDm2KMUcKqUEYIANMKAEx0iosBSMAdAMoAuSAJYA7AlwC2CANYoAFABZGAShABdeiACMLNrRAwBIggH1sAM2Mi+C5WtWqgA)

⇒ パフォーマンス計測して、共有できます。

[bsb-native](https://github.com/bsansouci/bucklescript)

⇒ OCamlにコンパイルできるそうです。ReasonMLをOCamlランタイムで動かしたい人向けですかね。何か面白いことができそうな予感が漂ってます。

# ちょっとした準備

ここから何度も実行するので、`package.json`の`scripts`に

```json
  "scripts": {
    "otameshi": "bsb -make-world && node lib/js/src/index.js",
  },
```

という風に、コンパイル＋実行を定義しておくと便利です。

`npm run otameshi`でお試し実行できます。

ここからが構文などの入門になります。

# let 束縛 [【公式で見る】](https://reasonml.github.io/docs/ja/let-binding)

ReasonMLで、宣言は「let」です。

```javascript
let hoge = "hoge";
```

JavaScriptの`const`みたいにイミュータブルです。

変数では無く「let 束縛」です。

```javascript
let hoge = "hoge";

// エラー！
hoge = "huga";
```

でも、再宣言はできます。

```javascript
let hoge = "hoge";

// これはOK
let hoge = "huga";
```

スコープは、`{}`の中だけです。いつもどおりです。

```javascript
{
  let hoge = "hoge";
}

// hogeがみつからないよって言われる
print_endline(hoge);
```

さらっと出てきた`print_endline()`は、`console.log`みたいなもんです。

## 【コーヒーブレーク】こんな書き方ができる

こんな感じの書き方ができます。

`++`が文字列結合です。

```javascript
let message = {
  let a = "hello";
  let b = "world";

  a ++ " " ++ b;
}

print_endline(message);
```

変換されたJavaScriptを見てみましょう。

```javascript
// Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE
'use strict';


var message = "hello world";

console.log(message);

exports.message = message;
/*  Not a pure module */
```

「Not a pure module」と教えてくれるのも気になりますが置いといて、

まず、スコープ`{}`内の式の結果は、コンパイルされて`"hello world"`という文字列になってます。

`print_endline()`は、`console.log`ですね。

最後に、`exports.message = message`

これはCommonJSの記法で、別のモジュールから`message`を参照できるようにするコードですね。

どうやらReasonMLでのトップレベルスコープの「let 束縛」は、`export`されるようです。

# 型！ [【公式で見る】](https://reasonml.github.io/docs/en/type)

まずは、型推論です。

```javascript
let num = 10;
print_endline(num);

// numは数字だよ！って言われる
let num = "hoge";
```

`10`は「Int」型なので、後の`"hoge"`という文字列型は再宣言できません。

明示的な型宣言も可能です。

`:`+ 型で、束縛の型を指定できます。

```javascript
let num: int = 10;
print_endline(string_of_int(num));

// 型が違うので怒られる
let num: int = "10";
```

ちゃっかり`string_of_int()`を使いましたが、`int`から`string`に変換する関数です。

`print_endline()`は、文字列を表示するので、型変換をしないとエラーになります。

これは、公式に出ている`add`関数の宣言です。

```javascript
let add = (x: int, y: int) : int => x + y;
```

このように戻り値の方も指定できるようです。

公式にはこんな感じの呪文の例も書かれています。

```javascript
let drawCircle = (~radius as r: int) : unit => ...;
```

あとで「関数」のところで説明できるようになるので、楽しみにしておくか、

間は飛ばして[ラベル付き引数](#ラベル付き引数)を見てください。

## 【コーヒーブレーク】使われなければ再宣言できる

冒頭のコードを下記のようにすると、コンパイルが通ります。

```javascript
let num = 10;

let num = "hoge";
```

コンパイル後のJavaScriptはこちらです。

```javascript
// Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE
'use strict';


var num = "hoge";

exports.num = num;
/* No side effect */
```

ちゃっかり「No side effect」って教えてくれるのも気になりますが置いといて、

そもそも`let num = 10`に対する部分は消えてます。

使われてないコードは、コンパイル後は消えているということです。

一応、Warningは出るので気づけます。

未使用のコードを削減することで、ファイルのサイズを抑えてくれているのですね。

# 文字列 [【公式で見る】](https://reasonml.github.io/docs/en/string-and-char)

文字列は`""`で囲みます。

エスケープは`\`

文字列結合は、`++`

でできます。

文字列内は改行ができます。

ただし、Unicodeをサポートしていませんので、ひらがな等を含めたい場合は、その為の書き方があります。後で説明します。

```javascript
let string = "hello 
world";

print_endline(string);
```

`{|`と`|}`というで囲むと、中がすべてエスケープされます。

```javascript
let greetingAndOneSlash = {|Hello
World
\
Hehe...
|};

print_endline(greetingAndOneSlash);
```

JavaScriptにコンパイルされると、

```javascript
var greetingAndOneSlash = "Hello\nWorld\n\\\nHehe...\n";
```

という風に、エスケープされていることがわかります。

`{js|`と`|js}`で囲むことでUnicodeが扱えます。

```javascript
let code = {js|한|js};

print_endline(code);
```

`{j|`と`|j}`で囲むことで置き換えができます。Unicodeもサポートしてます。

```javascript
let hoge = "world";
let helloWorld = {j|hello, $hoge|j};

print_endline(helloWorld);
```

`$hoge`が`"world"`に置き換わります。

# 真偽値 [【公式で見る】](https://reasonml.github.io/docs/en/boolean)

`true` / `false`です。いつも通りです。

演算子もほぼいつも通りです。

```javascript
true && false // false
true || false // true
!true // false
1 > 1 // false
1 >= 1 // true
1 < 1 // false
1 <= 1 // true
(1, 2) == (1, 2) // true
(1, 2) === (1, 2) // false
(1, 2) != (1, 2) // false
(1, 2) !== (1, 2) // true
```

あとにも書きますが、`(1, 2)`というのは、タプルです。

`==`は構造的な比較なので、内部の値が一致しているタプル同士はイコールと判定されます。

`===`は参照の比較なので、別のインスタンスとしてノットイコールと判定されます。

お分かりの通り、`==`は構造的な比較で、ネストされたデータについて再帰的に比較を行う為、**パフォーマンスに影響します**。

注意して使ってください。

# IntとFloat [【公式で見る】](https://reasonml.github.io/docs/en/integer-and-float)

Intは、32-bitの整数型です。

演算子もいつもどおりです。

```javascript
let hoge:int = 3 + 2 * 4 - 1 / 2;

print_endline(string_of_int(hoge));
```

計算結果は、`10.5`ですが出力は`11`です。

```javascript
let hoge:int = 3 + 2 * 4 - 1 / 2 * 2;

print_endline(string_of_int(hoge));
```

これで、`10`になるかと思いきや`11`でした。

バグなのか分からないので、今度Issue挙げてみます。

Intで割り算は避けた方がいいかもです。

Floatは、小数が扱えます。

演算子は、`+.` `-.` `*.` `/.`というように`.`が後につきます。

```javascript
let hoge:float = 3.1 +. 2.2 *. 4.3 -. 1.4 /. 2.5 *. 2.6;

print_endline(string_of_float(hoge));
```

こっちは計算合ってました。

# タプル [【公式で見る】](https://reasonml.github.io/docs/en/tuple)

`()`で囲むとタプル。

```javascript
// 型推論
let tuple1 = (1, 2.0, "3", '4', true);

// 型指定
let tuple2: (int, string) = (12, "34");

// 値を取り出す
let (_, y, z) = (1, 2, 3);

print_endline(string_of_int(y + z));
```

公式にもありますが、タプルは

- 不変
- 順序がある
- 作成時にサイズが決まる
- いろんな型をまぜこぜOK

らしいです。

パターンマッチングに使う方法が公式で紹介されています。

https://reasonml.github.io/docs/en/tuple#tips-tricks

`switch`とか関数はあとでやりますが、なんとなく分かるかと思います。

コンパイル後のJavaScriptコードを見たら、タプルはただの配列でした。

```javascript
// (1,2,3)
[1,2,3]
```

不変な配列みたいな感じですね。

# Record [【公式で見る】](https://reasonml.github.io/docs/en/record)

Recordは、JavaScriptのオブジェクトに近いようですが、早くて不変で型が持てます。

```javascript
// person型
type person = {
  age: int,
  name: string
};

// インスタンス
let me:person = {
  age: 5,
  name: "zzzzz"
};

let age = string_of_int(me.age);
let name = me.name;

let result = {j|$nameの精神年齢は$ageです|j};

print_endline(result);
```

型の宣言は必須です。

```javascript
let me = {
  // ageなんてプロパティは無いと怒られる
  age: 5,
  name: "zzzzz"
};
```

プロパティの型が違えば、コンパイルエラーです。

```javascript
// person型
type person = {
  age: int,
  name: string
};

// ageの型がダメ
let me:person = {
  age: "5",
  name: "zzzzz"
};
```

インスタンスの構造が型に即して無くてもエラーです。

```javascript
// person型
type person = {
  age: int,
  name: string
};

// 勝手にプロパティ追加しちゃだめ
let me:person = {
  age: 5,
  name: "zzzzz",
  extend: "hoge"
};
```

Recordは不変ですが、`...`を新しい束縛を作ることができます。

```javascript
// person型
type person = {
  age: int,
  name: string
};

// インスタンス
let me = {
  age: 5,
  name: "zzzzz"
};

// 新しいインスタンス（１歳成長しました）
let grown = {
  ...me,
  age: me.age + 1
}

let age = string_of_int(grown.age);
let name = grown.name;

let result = {j|$nameの精神年齢は$ageです|j};

print_endline(result);
```

省略記法も使うことができます。

```javascript
type address = {
  zip: string,
  country: string,
  state: string,
  city: string,
  street: string,
  room: string
}

type person = {
  age: int,
  name: string,
  // address: addressと一緒
  address
};

let zip = "111-1111";

let me = {
  age: 5,
  name: "zzzzz",
  address: {
    // zip: zipと一緒
    zip,
    country: "Japan",
    state: "Tokyo",
    city: "Shubuya",
    street: "oooooo",
    room: "102"
  }
};
```

## 【コーヒーブレーク】型は結局どうなるか

コンパイル後のJavaScriptを見てみましょう。

最初の例をコンパイルした結果です。

```javascript
// Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE
'use strict';


var age = String(5);

var name = "zzzzz";

var result = "" + (String(name) + ("の精神年齢は" + (String(age) + "です")));

console.log(result);

var me = {
  age: 5,
  name: "zzzzz"
};

exports.me = me;
exports.age = age;
exports.name = name;
exports.result = result;
/* age Not a pure module */
```

`Class`もないし、チェック処理もないです。

ほんとにただオブジェクト作ってるだけです。

当たり前ですが、あくまで静的解析でバグを検知してくれているだけなので、

ランタイム上で動くコードにReasonMLの型の概念はありません。

おかげでコンパイル時に型チェックは入りますが、コンパイル後のコードは軽量で高速です。

ありがたいですね。

# Variant! [【公式で見る】](https://reasonml.github.io/docs/en/variant)

型！の時とおなじように、「！」がついています。

それだけReasonMLにとって大事な機能ということらしいです。

ReasonMLのデータ構造における宝石の王冠とも表現されるVariantとはなんなのでしょうか？

とりあえずコードを見た方が早いです。

```javascript
type animal =
  | Dog
  | Cat
  | Hamaguchi;

let ilove = Dog;

let cried = switch ilove {
| Dog => {js|わん！|js}
| Cat => {js|なあぁ！|js}
| Hamaguchi => {js|気合いだ！|js}
};

print_endline(cried);
```

まず、animal型は、「Dog・Cat・Hamaguchi」のどれかであると宣言します。

このとき、Dogというように大文字で始まる必要があります。

（言ってませんでしたが、型は小文字始まりです）

これらはコンストラクターと呼ばれます。

私は犬が好きなので、`let ilove = Dog;`とします。

そして、その値を`switch`にかけると、中でマッチングされ、結果が返ります。

ここでは、Dogなので「わん！」と表示されます。

`animal`という型に「さまざまな」コンストラクターを持てるから、Variantなんでしょうか。

コンストラクタは引数を持てます。

```javascript
type animal =
  | Dog(int)
  | Cat(int)
  | Hamaguchi;

let ilove = Dog(3);

let description = switch ilove {
| Dog(age) => {j|$age歳の犬です。|j}
| Cat(age) => {j|$age歳の猫です。|j}
| Hamaguchi => {js|気合いだ！|js}
};

print_endline(description);
```

犬猫の情報として、年が指定できるようになり、`switch`の際は指定した年を参照できます。

ちなみにコンパイル後は、`if`文すらないです。

気になる方は、実際にコンパイルしてみてください。

## `option`と`list`

標準ライブラリには、２つのVariantsが事前に用意されています。

**`option`**は、Null許容を表現できます。

というのも、ReasonMLの型は全て非Null許容なので、値が入らないことを示すために`None`を用いることができます。

```javascript
type nullableInt = None | Some(int);

let numOrNull:nullableInt = None;

let result =
  switch numOrNull {
  | None => 0
  | Some(num) => num
  };

print_endline(string_of_int(result))
```

`None => `は、numOrNullが`None`の場合にマッチします。

`Some(num) => `は値が入っている場合にマッチします。

**`list`**は、ある任意の型aの値を空か１つ以上保持する。。。

つまり**リスト**を表現できます。

```javascript
type numberList = list(int);

let huga:numberList = [1, 2];

let result =
  switch huga {
  | [] => {js|空ですよ|js}
  | [a, b, ...rest] => string_of_int(a + b) ++ {js|ですよ|js}
  };

print_endline(result);
```

`[] => `の時は、リストが空の場合にマッチします。

`[a, b, ...rest] => `は、空でないリストにマッチし、一番目の値は`a`、二番目の値は`b`に入り、残りの要素は`rest`入ります。

# nullとundefined、そしてOption [【公式で見る】](https://reasonml.github.io/docs/en/null-undefined-option)

先ほども紹介した`option`を使って、null許容を表現できます。

電話番号は、電話を持っている人しかもっていないので、電話番号無し＝`None`の場合もあるとします。

```javascript
let personHasAPhone = true;

let phoneNumber =
  if (personHasAPhone) {
    Some("090-aaaa-bbbb")
  } else {
    None
  };

let result =
  switch phoneNumber {
  | None => ""
  | Some(number) => number
  };

print_endline(result);
```

このように`switch`で必ず`None`をハンドリングさせることで、意図しないバグの発生確率を下げることができます。

`None`はReasonML内での識別子ですが、JavaScript上では`undefined`になります。

`Some`コンストラクタは、`Some(Some(x))`のように`Some`を入れ子にできますが、その結果をそのままJavaScriptにコンパイルすると、

`Some(None)` ⇒ `Js_primitive.some(undefined);`のような意図しないコンパイル結果が出る可能性があるので避けましょう。

また、サードパーティなどのJavaScript側から渡された値に、`option`のような多態性のある型を割り当てるのもNGです。

intなどの具体的な型を割り当てましょう。

これについては、型システムは実行時のバリデーションを含まないので、ハンドリングできると勘違いしてしまうリスクを防いでいると勝手に思ってます。

また先ほど書いたように`None`は`undefined`です。`null`は含みません。

なので、JavaScriptから渡された値について「`null` or `undefined`」を判定する場合は、`Js.Nullable`モジュールを使うべきです。

結論的には、JavaScript側との相互運用において、`Some(None)`をJS側に出したり、JS側から貰った値を`option`として扱おうとすると、ハマるからやめといてね。。。ってことになりそうです。

間違ってたら誰か教えてください。すいません。

`Js.Nullable`モジュールについては、JavaScriptとの相互運用について記載するときに、説明しようと思います。

# リストと配列

ReasonMLには、リストと配列があり、それぞれ別物として扱われるようです。

## リスト

特徴として、

- 値は全部同じ型（タプルみたいに型まぜこぜはダメ）
- 不変
- 先頭への値の追加が高速

となります。

`[]`でリストの宣言ができます。

```javascript
let list = [2, 3, 4];

let newList = [1, ...list];

switch newList {
| [] => print_endline("It is empty...")
| [a, ...rest] => print_endline("value at first index is " ++ string_of_int(a))
};
```

`[1, ...list]`のようにして、新しい束縛の宣言とともに、先頭に値を追加しています。

先頭以外のインデックスへの差し込みは、計算量が増える（`O(n)`）ので、気を付けてください。

（ちなみに先頭への追加は`O(1)`）

**「値の取り出し」**は`switch`で行います。

リストへのアクセスで`switch`を使う機会は多いです。

【補足】将来的に、先頭以外のインデックスへの挿入に対してもパフォーマンスを保証するリストを追加する可能性はあるらしいです。

## 配列

- 変更可能
- ランダムアクセス・更新が高速
- 固定サイズ

`[|` と `|]`で配列の宣言ができます。

```javascript
let array = [|1, 2, 4|];

let before = array[2];

array[2] = 3;

let after = array[2];

print_endline({j|$beforeから$afterに変更しました。|j})
```

固定サイズで、中身を頻繁に変更する場合は「配列」を使いましょう。

# 関数 [【公式で見る】](https://reasonml.github.io/docs/en/function)

やっとこさ出てきた関数ですが、公式でも「ここまで関数を説明しませんでした。信じられますか？」と書いてます。（笑）

真面目な話、ここまでに紹介した機能を駆使すれば大抵の処理は書けそうですし、ここでの「関数」はある意味で可読性を落とす原因になるようにも思えます。

なので、ライブラリの関数のラッパーとか、四捨五入みたいなちょっとしたユーティリティなどの「中身知らない系」の処理作成に向いてそうです。

それはさておき、

構文は、JavaScriptのアロー関数に似ています。

```javascript
// 基本的な書き方
let greet = (name) => "Hello " ++ name;

// 実行
print_endline(greet("world"));

// 複数の引数
let add = (x, y, z) => x + y + z;

// ブロック
let greetMore = (name) => {
  let part1 = "Hello";
  part1 ++ " " ++ name
};
```

## 引数無しの関数

引数無しの関数は、ReasonMLでは「副作用」をもたらすものとして使われます。

```javascript
/* receive & destructure the unit argument */
let logSomething = () => {
  print_endline("hello");
  print_endline("world")
};

/* call the function with the value of type unit */
logSomething();
```

単純に、`() => ...`と書くわけですが、ReasonMLにおいて`()`は`unit`としての「値」として扱われるそうです。

`()`は`unit`として可能な唯一の値らしいです。

不便さと裏腹に、都合の悪い書き方として、あえて`()`を書かせる思想？みたいです。

副作用を記載する際は、このように「引数無しの関数」を使いましょう。

## ラベル付き引数

引数に名前をつけることができ、実行する際に名前付きで指定できます。

```javascript
let concat = (~a, ~b) => string_of_int(a) ++ b;

print_endline(concat(~a=2, ~b="3"));
```

`~a`は`~a as a`の省略記法なので、

```javascript
let concat = (~a as a, ~b as b) => string_of_int(a) ++ b;

print_endline(concat(~a=2, ~b="3"));
```

とおなじで、別名を付けることもでき、

```javascript
let concat = (~a as zen, ~b as go) => string_of_int(zen) ++ go;

print_endline(concat(~a=2, ~b="3"));
```

関数のスコープ内での引数のエイリアスを定義できます。

## カリー化

ReasonMLは、パフォーマンス劣化なく、自動でカリー化を行っています。

```javascript
let add = (a, b) => a + b;
```

と

```javascript
let add = (a) => (b) => a + b;
```

で、`add`の中身は一緒です。

つまり、先に書いた`add`関数に引数を**1個**しか渡さなかった場合は、関数（`(b) => a + b`）が返ってくるということです。

```javascript
let add = (a, b) => a ++ b;

// output: 23
print_endline(add("2", "3"));

// output: 23
print_endline(add("2")("3"));
```

## オプションの引数

引数を任意にするには、引数に`=?`を付けるだけです。

これにより引数が`option`型になり、`None`または`Some('a)`として扱えます。

`'a`は任意の型を指します。

```javascript
let add = (~a, ~b=?, ()) => {
  let num = switch b {
  | None => "0"
  | Some(num) => string_of_int(num)
  };

  a ++ num
}

print_endline(add(~a="2", ()));
```

`~b`は指定されていないので、`None`となり、"20"が出力されます。

引数の最後に、unit`()`を付ける理由を説明します。

先ほどのカリー化の説明をもとにすると、

```javascript
let add = (~a, ~b=?) => ...
```

という関数に対して

```javascript
add(~a)
```

は、

```javascript
(~b=?) => ...
```

となりますよね。

しかし、引数`b`は任意なので、`b`を指定しないで実行したいのか、カリー化したいだけなのか判断がつきません。

下記のコードはコンパイルエラーとなり、`b`を指定するよう怒られます。

```javascript
let add = (~a, ~b=?) => ...

print_endline(add(~a="2"));
```

そこで、OCamlにおける経験則として、引数にunit`()`を配置することをとすることで、

その位置までの引数を無視する、つまり`None`を指定して関数を実行することを明示できます。

よって、こんな風に`b`に`None`が指定された状態の関数を作りだし、最後に`c`を指定して実行できます。

```javascript
let add = (~a, ~b=?, (), ~c=?) => {
  a ++ switch b {
  | None => "0"
  | Some(num) => string_of_int(num)
  } ++ switch c {
  | None => "0"
  | Some(num) => string_of_int(num)
  };
}

let add2 = add(~a="2", ());

print_endline(add2(~c=3));
```

こんなまどろっこしいこと普通はやらなそうですが、例えばNPMライブラリとして公開する場合には、

`exports.add`の引数を一部束縛した状態の関数として、`exports.add2`を公開できます。

こういった仕様があることを知っておくに越したことはなさそうですね。

## Explicitly Passed Optional

オプショナルな引数を、別の関数に渡すときは、どういう風に書くことになるでしょう。

```javascript
let concat = (~a, ~b=?, ()) => a ++ switch b {
| None => "0"
| Some(num) => string_of_int(num)
};

let add = (~a, ~b=?, ()) => switch b {
| None => concat(~a=a, ())
| Some(num) => concat(~a=a, ~b=num, ())
};

print_endline(add(~a="1", ()));
```

よく見てもらうと、`add`関数がやっていることは、引数`b`がNoneかどうか判断し、`concat`関数に対して指定するかしないかを切り替えているだけです。

こうした冗長な記述に対する省略記法があります。

```javascript
let concat = (~a, ~b=?, ()) => a ++ switch b {
| None => "0"
| Some(num) => string_of_int(num)
};

// このように省略できる
let add = (~a, ~b=?, ()) => concat(~a, ~b=?b, ());

print_endline(add(~a="1", ()));
```

関数を呼び出す際の引数の指定で、`=?`を使い`option`型の値を指定することで、`switch` + `None` + `Some`のパターンマッチングに対する省略記法となります。

## デフォルト値の指定

任意の引数に対するデフォルト値の指定ができます。

```javascript
let add = (~a, ~b=0, ()) => a ++ string_of_int(b);

print_endline(add(~a="1", ()));
```

`b`は指定されない場合、`0`になり、`int`として扱われます。

## 再帰的関数

基本的に、`let a = () => a()`のような自身への参照の仕方はできないのですが、

`rec`をつかうことで、可能になります。

```javascript
let rec floorSum = (a) => switch a {
| 0 => a
| n => a + floorSum(n - 1)
};

print_endline(string_of_int(floorSum(3)));
```

## 相互で呼び出される再帰的関数

`a()`の中で`b()`を呼び、`b()`の中で`a()`が呼ばれるパターンです。

`rec`と`and`を使います。

```javascript
let rec callSecond = () => callFirst()
and callFirst = () => callSecond();
```

良い具体例が浮かばず、公式をパクりました。すいません。

## 引数の型や、関数の型（インターフェース）を指定する

ここまでで説明しなかったので、一応書いておきます。

```javascript
// 引数の型の指定
let add = (x: int, y: int) => x + y;

// 関数の型＝インターフェースの指定
let add: int => int => int = (x, y)=> x + y;

print_endline(string_of_int(add(3, 1)));
```

## 【コーヒーブレーク】Intが戻り値の関数

一番最後の例のコンパイル結果を見てみましょう。

```javascript
// Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE
'use strict';


function add(x, y) {
  return x + y | 0;
}

console.log(String(4));

exports.add = add;
/*  Not a pure module */
```

`x + y | 0`ってなんぞ？って思いませんか？

これは、戻り値がNaNになるのを防止しているのだと思います。

ReasonMLで作った`Int`が戻り値の関数は、`| 0`が付くのかもしれません。

引数にnullとかが渡るとエラーではなく「0」になるとすると、実行時例外は防げるものの、意図しない動作になる可能性もありますよね。

もちろん完全にReason Worldの中だけなら問題ないのですが、ReasonMLで作りNPMで外部公開したライブラリを使ってもらって、意図しない挙動になるのは困ります。

可用性の観点ではもちろん良いですが、綿密な計算を行うシステムに多少不向きであるのはJavaScriptと同様ですね。

一応、知っておくべきでしょう。

# If-Else [【公式で見る】](https://reasonml.github.io/docs/en/if-else)

If-Elseは条件を評価し、対応するブロック内の式の評価結果を戻り値として返します。

```javascript
let result = if (true) {
  "true result"
} else {
  "false result"
}

print_endline(result);
```

IfとElseブロックの評価結果の型は同一である必要があります。

ある条件で「ログを出力をする」などの戻り値のない副作用などの処理分岐はこのようにかきます。

```javascript
let result = if (true) {
  let log = () => print_endline("it is true");

  log()
};
```

これは

```javascript
let result = if (true) {
  let log = () => print_endline("it is true");

  log()
} else {
  ()
};
```

のシンタックスシュガーで、戻り値がunit`()`になります。

よってこのような式はコンパイルエラー（unit`()` ≠ string）です。

```javascript
let result = if (true) {
  "true result"
}
```

## 三項演算子

もちろん三項演算子も使えます。

```javascript
let res = true ? "true" : "false";

print_endline(res);
```

# Pipe First [【公式で見る】](https://reasonml.github.io/docs/en/pipe-first

`->` 演算子を使うことで、パイプ表現ができます。

たとえば、このように関数の入れ子が多すぎる式は

```javascript
let add = (num) => num + 2;
let minus = (num) => num - 3;
let times = (num) => num * 4;

print_endline(
  string_of_int(
    times(minus(add(1)))
  )
);
```

このようにパイプで表現できます。

```javascript
let add = (num) => num + 2;
let minus = (num) => num - 3;
let times = (num) => num * 4;

1
  ->add
  ->minus
  ->times
  ->string_of_int
  ->print_endline
```

`a(b)`を、`b->a`と表現できるということになります。



複数の引数を持つ関数の場合は、

```javascript
let add = (x, y, z) => x + y * z;

1 ->add(2, 3)
  ->string_of_int->print_endline;
```

というように書けます。ラベル付き引数の場合でも同様です。

```javascript
let add = (x, ~y, ~z) => x + y * z;

1 ->add(~y=2, ~z=3)
  ->string_of_int->print_endline;
```

ただし、パイプを使いすぎるのは、良いこととは限らず、新しくReasonMLを始めた人は、この軽快な書き方に頼って、すべてパイプにしようとしてしまうらしいです。

公式では、このように中心的な処理に対する付加的な処理としてパイプをつけることを勧めてます。

```javascript
parseData(person)
  ->getAge
  ->validateAge
```

このようにIntの値を表示させたいときに、ちょっと便利だったりもします。

```javascript
1024
  ->string_of_int->print_endline
```

## JavaScriptのメソッドチェーン

JavaScriptでは、

```javascript
[1,2,3].map(x => x + 1).filter(x => x % 2 === 0);
```

というようにメソッドチェーン形式で式を記載できます。

これをReasonMLでやろうとすると

```javascript
filter(map([|1,2,3|], x => x + 1), x => x mod 2 === 0);
```

となり、ちょっぴり見づらくなってしまいますが、

```javascript
[|1,2,3|]
  -> map(x => x + 1)
  -> filter(x => x mod 2 === 0)
```

と書けるので、嬉しいね。っていう話でした。

※ `filter`や`map`はデフォルトで存在するわけではなく、Js側からもらってこないといけません。

[BuckleScript binding API](https://bucklescript.github.io/docs/en/function#object-method)を利用する必要があります。

実際はこのように記載することで、利用することができます。

```javascript
[@bs.send] external map : (array('a), 'a => 'b) => array('b) = "map";
[@bs.send] external filter : (array('a), 'a => 'b) => array('b) = "filter";

[|1,2,3|]
  -> map(x => x + 1)
  -> filter(x => x mod 2 === 0)
```

## VariantsへのPipe

`option`で、`Some('a)`ってありましたよね。

`Some`はコンストラクタであって、関数ではないですが、パイプすることができます。

```javascript
let result = name->preprocess->Some;

let result = Some(preprocess(name));
```

上記２つは一緒です。（また良い例が浮かばず、公式パクりで申し訳ない。）

コンストラクタは、あくまで関数ではなく、このパイプ表現以外で、関数と同様に扱える場面は無いそうです。

パイプは、実はただ１つ前を`(` `)`で囲む変換を施しているだけなのかもしれないですね。

ただこれ、どういうときに使うんでしょうね。

`preprocess`が外部コードの時とかになるのでしょうか？

JavaScript相互運用の説明をするときに、謎は解けるかもしれません！

## Pipe プレースホルダー

プレースホルダーは、関数を実行する際の引数を`_`にすることで、ある値を受け取り、`_`の位置に指定して実行される関数にできる記法です。（語彙が崩壊してる…）

例を見せます。

```javascript
let add = (x, y, z) => x + y + z;

// プレースホルダー記法は
let add4 = add(1, _, 3);

// これと同じ意味
let add4 = y => add(1, y, 3);

add4(2)
 ->string_of_int->print_endline;
```

このプレースホルダーを使うことで、パイプする引数をどの位置に渡すかを指定できます。

```javascript
let concat = (x, y) => x ++ y;

"1"->concat("2")
   ->print_endline; // result:12

"1"->concat("2", _)
   ->print_endline; // result:21
```

2個目は、プレースホルダーを使って、2番目の引数に`"1"`を渡しているので、結果が変わります。

# 型をもっと[【公式で見る】](https://reasonml.github.io/docs/en/more-on-type)

すでに「型！」は説明しましたが、更なる使い方の説明になります。

## 型引数！

いわゆるジェネリック型が定義できます。

ジェネリック型には、`'`を付けます。

たまに出てきた`'a`はジェネリック型だったということです。

下記のように、データ構造が等しく、別の型のデータを持つ場合に、

```javascript
type intTuple = (int, int);
type floatTuple = (float, float);
```

型引数を使えると、よりインスタントに型を生成できます。

```
type twinTuple('t) = ('t, 't);

type intTuple = twinTuple(int);
type floatTuple = floatTuple(int);
```

`option`と同等の、ジェネリック型を作成することもできます。

```javascript
type ninni('concrete) = None | Some('concrete);

let num: ninni(int) = None;

let resnum = switch num {
| None => 0
| Some(n) => n
};
resnum->string_of_int->print_endline;

let str: ninni(string) = None;
let resstr = switch str {
| None => "empty"
| Some(s) => s
};
resstr->print_endline;
```

公式には、より複雑に組成された構造が紹介されてます。

興味があったら、見てください。

## 相互に参照する再帰的な型

お互いにお互いの型を参照するケースです。

`type`と`and`を使います。

```javascript
type person = { owns: list(dog) }
and dog = { ownedBy: option(person) };

let me: person = {
  owns: []
};

let norainu: dog = {
  ownedBy: None
};
```

## Destructuring

デストラクチャリングです。

構造データを分解して、束縛に代入できます。

タプルの分解例です。

```javascript
let tuple = (1, 2);
let (a, b) = tuple;

(a + b)
  -> string_of_int -> print_endline;
```

レコードの分解例です。

```javascript
type example = { a: int, b: int };
let record: example = { a: 1, b: 1 };

let { b, a } = record;

(a + b)
  -> string_of_int -> print_endline;

// ラベル付けもできます
let { b: bbb, a: aaa } = record;

(aaa + bbb)
  -> string_of_int -> print_endline;
```

型アノテーションもつけることができます。

```javascript
let (a: int, b: int) = someInts;
let {a: (aaa: int), b: (bbb: int)} = someInts;
```

なぜか公式では触れられていませんが、配列もできます。

```javascript
let [a, b] = [1, 2];

(a + b)
  -> string_of_int -> print_endline;
```

関数のラベル付き引数も分解できます。

```javascript
let addTuple = (~tuple as (x, y)) => x + y;

addTuple(~tuple=(1, 2))
  -> string_of_int -> print_endline;
```

分解していない状態の引数に、別のラベルを付けることができます。

```javascript
type record = {
  x: int,
  y: int
};

let add = (~record as {x, y} as pair) => x + y + pair.x + pair.y;

add(~record={ x: 1, y: 2})
  -> string_of_int -> print_endline;
```

# パターンマッチング！[【公式で見る】](https://reasonml.github.io/docs/en/pattern-matching)

Variantの章は読まれましたか？

読んでいないなら、先にそちらを読んでください。と公式がおっしゃっています。

`switch`で良く使った`|`によるものです。

たとえば、HTTPレスポンスのハンドリングに使えます。

```javascript
type person = {
  name: string,
  age: int
};

type response =
  | Ok(list(person))
  | BadRequest(string)
  | InternalServerError;

let res = Ok([{
  name: "taro",
  age: 10
}, {
  name: "jiro",
  age: 8
}]);

switch (res) {
| Ok(persons) => {
    let [taro, jiro] = persons;
    print_endline(taro.name ++ " and " ++ jiro.name);
  }
| BadRequest(message) => print_endline(message);
};
```

上の例では、レスポンスには、「`OK`、`BadRequest`、`InternalServerError`」を定義しました。

しかし`switch`では、「`OK`、`BadRequest`」しかマッチングさせていません。

この場合エラーにはなりませんが、警告が出ます。

```
// `InternalServerError`のことを忘れていませんか？
You forgot to handle a possible case here, for example:
InternalServerError
```

みんな大嫌い`UnhandledPromiseRejectionWarning()`とか防げそうですね。（笑）

条件分岐としての使い方もできます。

```javascript
let num = 4;

let result = switch num {
| 1 => "1"
| 2 => "2"
| 3 => "3"
| _ => {js|数値です|js}
};

result
 ->print_endline;
```

`_`は、他がすべてマッチしなかったときのフォールスルーです。

コンストラクタに含まれる値を指定したマッチングもできます。

```javascript
type person = {
  name: string,
  age: int
};

type response =
  | Ok(list(person))
  | BadRequest(string)
  | InternalServerError;

let res = BadRequest("CODE1-1");

switch (res) {
| Ok(persons) => {
    let [taro, jiro] = persons;
    print_endline(taro.name ++ " and " ++ jiro.name);
  }
| BadRequest("CODE1-1" | "CODE1-2" | "CODE1-3") => print_endline({js|コード１のエラーです|js});
| BadRequest(message) => print_endline({j|不明なエラー: $message|j});
| InternalServerError => print_endline("サーバーエラー")
};
```

リストなどのデータ構造とのマッチングもできます。

```javascript
let items = [1,2,3];

let result = switch items {
| [] => "0"
| [x, y] => string_of_int(x + y)
| [x, y, z] => string_of_int(x + y + z)
| [a, ...rest] => "too many items!"
};

result
  -> print_endline;
```

もちろんレコードでもできます。

```javascript
type person = {
  name: string,
  age: int
};

let taro: person = {
  name: "taro",
  age: 10
};

let who = switch taro {
| {name: "taro", age: 10} => "this is taro."
| {name: "jiro", age: 8} => "this is jiro."
| _ => "who?"
};

print_endline(who);
```

## when句

`when`句を使うことで、マッチングに条件を追加できます。

```javascript
type person = {
  name: string,
  age: int
};

type response =
  | Ok(list(person))
  | BadRequest(string)
  | InternalServerError;

let res = BadRequest("no-error");

switch (res) {
| Ok(persons) => {
    let [taro, jiro] = persons;
    print_endline(taro.name ++ " and " ++ jiro.name);
  }
| BadRequest(message) when message === "no-error" => print_endline({js|エラーではなかったようです|js});
| BadRequest(message) => print_endline({j|不明なエラー: $message|j});
| InternalServerError => print_endline("サーバーエラー")
};
```

## 例外のハンドリング

例外はまだ説明していませんが、こういうことができることだけ説明します。

`exception`句を使うことで、評価された値がエラーを含む場合のマッチングができます。

```javascript
switch (mayThrowError()) {
| result => print_endline(result)
| exception A_Error => print_endline("error message!")
};
```

## ネストされたパターン

データ構造に対するパターンマッチングができることを説明しました。

データ構造がネストしていても、それは可能です。

```javascript
type friend = {
  name: string
}

type person = {
  name: string,
  friend: friend
};

let taro = {
  name: "taro",
  friend: {
    name: "jiro"
  }
};


let result = switch taro {
| { friend: { name: "jiro" } } => {js|jiroが友達です|js}
| _ => "who?"
};

print_endline(result);
```

## パターンはどこでも使える

実は`switch`に限らず、let bindingでも使えます。

```javascript
type name =
  | FirstName(string)
  | LastName(string);


let taro = FirstName("taro");

let FirstName(name) | LastName(name) = taro;

print_endline(name);
```

# Mutation [【公式で見る】](https://reasonml.github.io/docs/en/mutation)

`ref`を使うことで、let bindingを変更できるようにします。

箱が作られ、その中に値が入っている状態をイメージします。

```javascript
let num = ref(0);

let zero = num^;

num := 3;

num^
  ->string_of_int->print_endline;

zero
  ->string_of_int->print_endline;
```

箱の中の値の変更は、`:=`で、

箱の中の値の取り出しは、`^`で行います。

`num`は、箱（`ref`）そのもの、`zero`は値になります。

ただし`ref`を使う前に、`let`が再宣言できることを忘れないでください。

```
let hoge = "ho";
let hoge = hoge ++ "ge";

print_endline(hoge)
```

# 命令的ループ [【公式で見る】](https://reasonml.github.io/docs/en/imperative-loops)

`map`や`filter`を使う以外に、列挙型の操作に使える構文が用意されています。

## Forループ

`for x in xFrom to xTo {}`が使えます。

```javascript
for (i in 1 to 10) {
  print_int(i);
}
```

（`print_int`なんて便利なものがあったとは露知らず。）

`downto`で、大きい値から小さい値へのループもできます。

```javascript
for (i in 10 downto 1) {
  print_int(i);
}
```

## Whileループ

`while(condition) {}`です。

```javascript
let x = ref(10);

while(x^ > 0) {
  print_int(x^);

  x := x^ - 1;
}
```

# JSX [【公式で見る】](https://reasonml.github.io/docs/en/jsx)

ReasonMLでは、JSX記法が使えます。

JSX記法が必ずしも可読性に寄与するかどうかの議論は、[こちら](https://github.com/flutter/flutter/issues/11609)が参考になります。

```javascript
let hoge = (~foo, ~children, ()) => {
  print_endline(foo);

  switch children {
  | [child1, child2] => print_endline(child1 ++ " " ++ child2)
  | _ => print_endline("invalid children")
  };
}

let bar = "bar";
let child1 = "taro";
let child2 = "jiro";

<hoge foo={bar}>child1 child2</hoge>;
```

`hoge`は関数で、`foo`属性は引数`foo`に、子要素に指定したchild1とchild2は引数`children`にリストで入ります。

これは`<hoge>`が、下記のコードに変換されるためです。

```javascript
([@JSX] div(~foo=bar, ~children=[child1, child2], ()));
```

公式を見ると、他にもいくつかのルールが紹介されていますので、よかったら見てみてください。

# External [公式で見る](https://reasonml.github.io/docs/en/external)

ReasomMLには、`external`または、FFI **f**oreign **f**unction **i**nterface という機能があります。

下記のコードを見てください。

```javascript
[@bs.val] external jsAlert: string => unit = "alert";

jsAlert("work only in browser.");
```

これがJavaScriptにコンパイルされると、

```javascript
// Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE
'use strict';


alert("work only in browser.");

/*  Not a pure module */
```

となります。

`@bs.val`の役割は、`"alert"`というJavaScriptのグローバル空間の値に対するアクセスを提供することです。

つまりこのコードはブラウザ環境でしか動きません。

ReasonMLにおける相互運用機能とは、コンパイラ（ここではBuckleScript）に対するヒントなので、

コンパイル後のコードが、

- Cのコンパイラが読めるならC言語との相互運用も可能ですし、

- ブラウザで動くなら、JavaScriptとの相互運用も可能だということです。

あくまで、ReasonML内で使うにはインタフェースを定義して、型を明示する必要があるということです。

この型システムはReasonML内でのモノで、外界のコードには適用されません。

これは、実行時エラーの主な原因にもなると思います。

外界のコードが持つ良い点も悪い点も受け入れるということなので、導入には慎重になるべきだと思います。

最後にもう一つ、`@bs.send`を紹介します。

```javascript
[@bs.send] external map : (array('a), 'a => 'b) => array('b) = "map";

map([|1, 2, 3|], x => x * 2)
```

これは、

```javascript
// Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE
'use strict';


/* array */[
    1,
    2,
    3
  ].map((function (x) {
        return (x << 1);
      }));

/*  Not a pure module */
```

にコンパイルされます。

第１引数に指定する値が持つメソッドとして、コンパイルされます。

JavaScriptのメソッドチェーンを、ReasonMLの関数にマッピングするときに便利です。

[Pipe Firstでも説明しました](#javascriptのメソッドチェーン)が、Pipeを使ってメソッドチェーン風に書くこともできます。

他にもいろんな`bs-blabla`があり、こちらで紹介されているので興味がある方は参照してみてください。

https://github.com/moroshko/bs-blabla

# 例外処理 [【公式で見る】](https://reasonml.github.io/docs/en/exception)

`exception`で定義したエラーを`raise`で発生させています。

`try`を用いて、エラーハンドリングします。

```javascript
exception A_Error;

let hoge = (x) => {
  if (x mod 2 === 0) {
    raise(A_Error)
  } else {
    1
  }
};

let res = try (hoge(2)) {
  | A_Error => 0
};

print_int(res);
```

variantのような使い方も可能です。

```javascript
exception A_Error(string);

let hoge = () => {
  raise(A_Error("error message"))
};

try (hoge()) {
  | A_Error(message) => print_endline(message)
};
```

ただし公式には、`try`はデモンストレーションとして使って見せたもので、実際は`switch` + `exception`を使ってくれと書いてあります。

[パターンマッチング - 例外のハンドリング](#例外のハンドリング)

これらは例外的なケースでのみ利用することが推奨され、乱用をさけるよう公式では書かれています。

[String](https://reasonml.github.io/api/String.html)や[List](https://reasonml.github.io/api/List.html)は、例外を発するので、使うときは気をつけてください。

# オブジェクト [【公式で見る】](https://reasonml.github.io/docs/en/object)

Recordに似てますが、JavaScriptにおけるオブジェクトというよりは`class`みたいな感じです。

`.`を使って、'closed'オブジェクトを定義します。

'closed'オブジェクトには、型に定義されていないメソッドを後から追加することができません。

```javascript
type person = {
  .
  name: string
};

let taro: person = {
  val _name = "taro";
  pub name = _name;
};

print_endline(taro#name);
```

`pub`は`public`メソッド。

`pri`は`private`メソッドです。

`val`はプロパティで、`private`です。

`.が２個、つまり`..`は'open'なオブジェクトを定義します。

'open'なオブジェクトは、定義されたインターフェース以外にメソッドやプロパティを持つことができます。

イメージですが、`person`を抽象クラスとして、`koseki`に拡張しています。

`this`の説明の都合で、`pub adjustName`から`pri changeName`を呼び出せます。

```javascript
type person('a) = {
  ..
  name: string
} as 'a;

type koseki = {
  .
  name: string,
  adjustName: string => unit
};

let taro: person(koseki) = {
  val _name = ref("toro");
  pub name = _name^;
  pub adjustName = (name) => this#changeName(name);
  pri changeName = (name) => {
    _name := name;
  };
};

taro#adjustName("taro");

print_endline(taro#name);
```

# モジュール [【公式で見る】](https://reasonml.github.io/docs/en/module)

ReasonMLにおけるモジュール化です。

`module`で定義し、型定義やlet bindingsを含むことができ、ネストもできます。

```javascript
module Example = {
  type meanless = Hoge | Huga | Piyo;

  let hoge = Hoge;
  
  let getMeanlessName = (x) => switch x {
  | Hoge => "hoge"
  | Huga => "huga"
  | Piyo => "piyo"
  };
}

let piyo: Example.meanless = Example.Piyo;

Example.getMeanlessName(piyo)
  -> print_endline;
```

## open

`open`を使うことで、モジュール名 + `.`を付けなくてよくなります。

```javascript
module Example = {
  type meanless = Hoge | Huga | Piyo;

  let hoge = Hoge;
  
  let getMeanlessName = (x) => switch x {
  | Hoge => "hoge"
  | Huga => "huga"
  | Piyo => "piyo"
  };
}

open Example;

let piyo: meanless = Piyo;

getMeanlessName(piyo)
  -> print_endline;
```

この例だと、グローバル空間への展開ですが、ローカルにも展開できます。

```javascript
module Example = {
  type meanless = Hoge | Huga | Piyo;

  let hoge = Hoge;
  
  let getMeanlessName = (x) => switch x {
  | Hoge => "hoge"
  | Huga => "huga"
  | Piyo => "piyo"
  };
}

let result = {
  open Example;

  let piyo: meanless = Piyo;

  getMeanlessName(piyo)
}

// グローバルスコープで meanless は参照できないからエラー
let huga: meanless = Huga;

print_endline(result);
```

## モジュール拡張

別のモジュールで`include`を使い、ベースとなるモジュールを拡張できます。

こちらは`mixin`的な使い方です。

```javascript
module Base = {
  let x = "x";
};

module Inheried = {
  include Base;
  let y = "y";
};

print_endline(Inheried.x);
```

## `.re`ファイルはモジュールそのもの

`index.re`とは別に、`sample.re`ファイルを作成してください。

```javascript:sample.re
let a = 1;
```

この`sample.re`は、`Sample`モジュールとして、他のファイルから呼び出しできます。

```javascript:index.re
print_int(Sample.a);
```

もちろん、`index.re`も`Index`モジュールとして利用できます。

## シグネチャ

モジュールの仕様？インターフェース？のことをシグネチャと呼びます。

`module type`を使って、シグネチャを定義します。

```javascript
// Animalのシグネチャ
module type Animal = {
  type species = Dog | Cat | Pig;

  let getCry: species => string;
};

// Animalのモジュール（実装）
module Animal: Animal = {
  type species = Dog | Cat | Pig;

  let getCry = specie => switch (specie) {
  | Dog => {js|ワン|js}
  | Cat => {js|にゃあ|js}
  | Pig => {js|ブヒ|js}
  };
};

let result = {
  open Animal;

  getCry(Dog);
};

print_endline(result);
```

## シグネチャの拡張

モジュールと同じで、`include`で拡張できます。

```javascript
module type Base = {
  let a: string;
};

module type Inherited = {
  include Base;

  let b: int;
};
```

またすでに実装されているモジュールを拡張して、シグネチャとして定義することもできます。

```javascript
module Base = {
  let a = "a";
};

module type Inherited = {
  include (module type of Base);

  let b: int;
};
```

## `.rei`ファイルは、シグネチャそのもの

`animal.rei`ファイルを作成します。

```javascript:animal.rei
type species = Dog | Cat | Pig;

let getCry: species => string;
```

これに対して、同名の`.re`ファイルを実装する必要があります。

```javascript:animal.re
type species = Dog | Cat | Pig;

let getCry = specie => switch (specie) {
| Dog => {js|ワン|js}
| Cat => {js|にゃあ|js}
| Pig => {js|ブヒ|js}
};
```

これで、`Animal`モジュールを利用できます。

```javascript:index.re
let result = {
  open Animal;

  getCry(Dog);
};

print_endline(result);
```

## モジュール関数（functors）

functorsとは、モジュールを引数として渡せる関数のことみたいです。

functorsは、

- `let`ではなく、`module`で宣言する
- モジュールを引数に取り、モジュールを返す
- 引数は、アノテーションが必要
- 大文字から始まる

を満たします。

公式の例を使わせてください。

```javascript
module type Comparable = {
  type t;
  let equal: (t, t) => bool;
};

module MakeSet = (Item: Comparable) => {
  /* let's use a list as our naive backing data structure */
  type backingType = list(Item.t);
  let empty = [];
  let add = (currentSet: backingType, newItem: Item.t) : backingType =>
    /* if item exists */
    if (List.exists((x) => Item.equal(x, newItem), currentSet)) {
      currentSet /* return the same (immutable) set (a list really) */
    } else {
      [
        newItem,
        ...currentSet /* prepend to the set and return it */
      ]
    };
};
```

これらを使い

```javascript
module IntPair = {
  type t = (int, int);
  let equal = ((x1, y1), (x2, y2)) => x1 == x2 && y1 == y2;
  let create = (x, y) => (x, y);
};

/* IntPair abides by the Comparable signature required by MakeSet */
module SetOfIntPairs = MakeSet(IntPair);

let result = SetOfIntPairs.add([
  (1, 2),
  (3, 4)
], IntPair.create(1, 2))

Js.log(result);
```

このように、ジェネリック的な使い方ができます。

# Promise [【公式で見る】](https://reasonml.github.io/docs/ja/promise)

ReasonMLには、JavaScriptのPromiseの機能へのBuckleScriptによるバインディングがビルトインサポートされてます。

```javascript
let promise = Js.Promise.make((~resolve, ~reject) => {
  Js_global.setTimeout(() => resolve(. "hello "), 2000);
  ()
});

promise
|> Js.Promise.then_(value => {
     Js.Promise.resolve(value ++ "world");
   })
|> Js.Promise.then_(value => {
     print_endline(value);
     Js.Promise.resolve(value);
   })
|> Js.Promise.catch(error => {
     Js.log(error);
     Js.Promise.resolve("failed");
   })
```

`Js_global.setTimeout`を使って２秒後にメッセージを出しています。

`resolve`関数を呼び出す際に`.`がついています。

`Js.Promise.make: ( ( ~resolve: (. 'a) => unit, ~reject: (. exn) => unit ) => unit ) => Js.Promise.t('a)`

このように、`resolve`関数の引数の定義に`.`がついていて、これは`resolve`関数をカリー化しないでねっていうコンパイラへの指示になります。

つまり任意の引数を除き、すべての引数を１度に指定する必要があります。

`|>`は、パイプ演算子の一種です。

```javascript
let add = (a, b) => a + b;

let result = 1 |> add(2);

print_int(result);
```

`|>`の前の値を引数として、`|>`の後ろの関数を実行します。

カリー化により、`add(2)`は引数を１つ取る関数（`b => 1 + b`）なので、1を引数に与えて実行した結果、3を返します。

# ライブラリを使う

## Redex [公式](https://redex.github.io/)

Redexは、ReasonML用のライブラリインデックスです。

作ったライブラリは、[こちら](https://redex.github.io/publish)から登録することができます。

`npm publish`するかどうかは任意で、実験的な機能や、開発中のライブラリを一旦Redexに登録しておいて、先に公開だけしたり、Contributeしてもらったりすることができます。

大抵のライブラリは、NPMのレジストリに公開してあって、そこから`npm install`できます。

その後、`bsconfig.json`内の`bs-dependencies`または`bs-dev-dependencies`を編集します。

[bs-dependencies, bs-dev-dependencies](https://bucklescript.github.io/docs/en/build-configuration.html#bs-dependencies-bs-dev-dependencies)

たとえば[`bs-css`](https://redex.github.io/package/bs-css)というパッケージをインストールする際は、

```bash
npm install --save bs-css
```

`bs-dependencies`に配列で、依存パッケージを指定します。

```json:bsconfig.json
{
  "name": "reason-sample",
  "sources": ["src"],
  "bs-dependencies": ["bs-css"]
}
```

これで、`Css`モジュールが使えます。

```javascript
Open Css
```

## npmのJSライブラリの利用 [bs-blablaで見る](`@bs.module`)

`@bs.module`を使えば、`require`で別のJSファイルへの参照

恐らくRedexに載ってるパッケージの多くが、これを使って既存のJavaScriptライブラリのラッパーを作り公開しているのではないかと思います。

このように記載したReasonMLが、

```javascript
[@bs.module] external uuidv4: unit => string = "uuid/v4";

Js.log(uuidv4());
```

このようにコンパイルされることで、npmライブラリを`require`できます。

```javascript
var V4 = require("uuid/v4");

console.log(V4());
```

# さいごに

OCamlは触ったことないですが、ReasonMLは抵抗少なめでした。

コードは可読性の為に冗長になることがあるので、コンパイルにより不要なコードが削除されたり、パフォーマンスが良いプログラムを組めるのはうれしいです。

実行時例外は普通に起こるかと思われますが、JavaScriptよりバグが少なく書けるかなと言う感じです。

JavaScriptとの比較ばかりしているので、AltJSとしての紹介になってしまいましたが、あくまでそれはBuckleScriptとの組み合わせの話です。

ReasonMLには、型とかnullが辛いと思われてるような別の言語との相互運用の可能性も残されているように感じます。

シンプルな言語だと舐めてかかったら、いろいろ機能を持っていて、ただ実際にはlet binding・Variants・パターンマッチング・型などコアとする部分があり、そこに対して便利さの為にモジュールが追加されていったような感じがしました。気のせいですかね。

各章にその機能に関連したReasonMLの思想や実際の実装上の活用法が、「Design Decisions」や「Tips & Tricks」として書かれているので、ぜひ読んで頂きたいところです。

自身も入門しながらのせいで、ところどころ質問混ざっちゃってますが、誰かのお役に立てたら幸いです。

さて、ここまで長くなりましたが、読んで頂きありがとうございました～。