OCaml の環境構築


**最初に以下のリンクのいずれかを一読することをオススメします。**

Real World OCaml に記載されている方法

- [Installation Instructions
](https://dev.realworldocaml.org/install.html)

OCaml Programming: Correct + Efficient + Beautiful に記載されている方法

- [Installing OCaml — OCaml Programming: Correct + Efficient + Beautiful](https://cs3110.github.io/textbook/chapters/preface/install.html)

京都大学工学部専門科目「プログラミング言語処理系」講義資料

- [OCaml 処理系のインストール](https://kuis-isle3sw.github.io/IoPLMaterials/HACKING.html)



## OPAM のインストール
- OPAM とは `OCaml PAckage Manager`
- パッケージマネージャだけど、OCaml本体もOPAMを通してインストールできる
    - なので最初にOPAMを入れる
    - OPAMのインストール時にOCamlが入るが、特に関係ない

Mac なら `brew install opam` する。

```
OPAM uses ~/.opam by default for its package database, so you need to
initialize it first by running (as a normal user):

$  opam init

Run the following to initialize your environment variables:

$  eval `opam config env`

To export the needed variables every time, add them to your dotfiles.
  * On Bash, add them to `~/.bash_profile`.
  * On Zsh, add them to `~/.zprofile` or `~/.zshrc` instead.

Documentation and tutorials are available at https://opam.ocaml.org, or
via "man opam" and "opam --help".

Bash completion has been installed to:
  /usr/local/etc/bash_completion.d

zsh completions have been installed to:
  /usr/local/share/zsh/site-functions
==> Summary
🍺  /usr/local/Cellar/opam/1.2.2_4: 31 files, 16.3MB
```

### OPAMの設定
- OPAMパッケージデータベース全体は、 `~/.opam` に保存される
- OPAMがおかしくなったら、 `~/.opam` を削除すれば初期化できる
- `opam init` のときに聞かれる質問は初心者は `y` しておけばよい
    - `opam init` は初回の1回でOK
- opamは基本的に管理者権限が必要なシステム領域に何かをインストールすることはない
    - 普通はホームディレクトリ `$HOME` に入る
    - よってホームディレクトリ配下のコマンドを叩けるように `PATH` を設定するコマンドがある
        - ```eval `opam config env` ```
    - `opam` の `$PATH` が設定済みかどうかは `echo $OCAML_TOPLEVEL_PATH` を確認すれば分かる

### コンパイラのバージョンを調べる
`opam switch` コマンドを使う

```
$ opam switch
--     -- 4.00.0  Official 4.00.0 release
--     -- 4.00.1  Official 4.00.1 release
--     -- 4.01.0  Official 4.01.0 release
--     -- 4.02.0  Official 4.02.0 release
--     -- 4.02.1  Official 4.02.1 release
--     -- 4.02.2  Official 4.02.2 release
4.02.3  I 4.02.3  Official 4.02.3 release
--     -- 4.03.0  Official 4.03.0 release
--     -- 4.04.0  Official 4.04.0 release
--     -- 4.04.1  Official 4.04.1 release
--     -- 4.04.2  Official 4.04.2 release
--     -- 4.05.0  Official 4.05.0 release
4.06.0  C 4.06.0  Official 4.06.0 release
system  I system  System compiler (4.06.0)
# 163 more patched or experimental compilers, use '--all' to show
```

もしシステムコンパイラが古い場合は以下のコマンドを叩く

```
$ opam switch 4.06.0 # 最新バージョンを指定する
```

`switch` コマンドは `.opam` 以下にOCamlコンパイラをソースからインストールする(なので時間かかる)。
新しいコンパイラと関連ライブラリは `.opam` 以下に入る。
上記の例だと `~/.opam/4.06.0` にインストールされる。

```
# PATHを反映する
$ eval `opam config env`

# ~/.opam 以下にOCamlコンパイラがインストールされている
$ which ocaml{,c,opt}
/Users/hoge/.opam/4.06.0/bin/ocaml
/Users/hoge/.opam/4.06.0/bin/ocamlc
/Users/hoge/.opam/4.06.0/bin/ocamlopt
```

あとは `opam install core utop hoge fuga` などして欲しいパッケージをインストールする

## utop の設定
`utop` はOCamlの対話環境
`$HOME` に設定ファイル `.ocamlinit` を置いておくと、ファイルに書かれた内容で初期化されて実行される。
なお `#foo` という表記はコメントではなく、対話環境向けの設定ディレクティブ。

`.ocamlinit` の例

```
#use "topfind";;
#thread;;
#camlp4o;;
#require "core.top";;
#require "core.syntax";;
open Core.Std
```

上記の設定ファイル例のように、`utop`でOPAM等で入れたモジュールを読み込む際には `#require "base"` とディレクティブで読み込んだあとに、`open Base;;` などする。

`utop` を入れるほどでもないときは `rlwrap ocaml` でも問題ない。

## Merlin
Merlin は OCaml の開発支援ツール。vim, emacs, vscode など様々なエディタで利用されている。
`opam install merlin` で入る。
使用するためにはブロジェクトの設定を `.merlin` ファイルで行う必要がある。
ただし `Dune` を使う場合は `.merlin` が自動生成されるので手書きすることは少ない。

公式リポジトリのWikiの [merlin の設定方法](https://github.com/ocaml/merlin/wiki/project-configuration) を参考に `.merlin` を記述する。

以下のブログ記事もとても参考になります。

- [OCaml: merlinでcompilerのコードを補完できるようにする](http://no-maddojp.hatenablog.com/entry/2014/12/01/022007)

### `S`ディレクティブ
ソースファイル(ml, mli)が置かれるディレクトリを指定する

```
# hoge と fuga ディレクトリをソースパスに指定する
S hoge
S fuga

# サブディレクトリを全部追加する
$ piyo/*

# foo以下のサブディレクトリを再帰的に追加する
S foo/**
```

### `B`ディレクティブ
cmi, cmtファイルの設置場所を設定する

```
B _build/hoge
B _build/fuga
B _build/* 
```

### `PKG`ディレクティブ
findlib(ocamlfind)で探せるパッケージを指定して、それを補完する。

```
PKG lwt lwt.unix
```

### `EXT`ディレクティブ
camlp4 で作成された拡張構文をサポートするが、廃止予定とのこと。

```
EXT lwt
```

### `FLG`ディレクティブ
merlinのオプションを有効にする, オプションの一覧は `ocamlmerlin server -flags-help` で参照可能

```
FLG -ppx path-to-executable
FLG -rectypes
```

### `REC`ディレクティブ
.merlinファイルの設定を親ディレクトリからも探すようにする

```
./.merlin            # RECの設定なし
./lib/.merlin        # RECディレクティブを記述した
./lib/first/.merlin  # RECディレクティブを記述した
./lib/second/.merlin # RECディレクティブを記述した
./src/.merlin        # RECディレクティブを記述した
```

`./.merlin` はその `.merlin` の設定のみ有効になる。
`./src` ディレクトリでは、`./src/.merlin` と親ディレクトリにある `./.merlin` の設定が有効になる
`./lib/first` ディレクトリでは、`./lib/first/.merlin` と親ディレクトリの `./lib/.merlin` と更にその親ディレクトリの `./.merlin` の設定が有効になる

## ocamlfind(findlib)
`ocamlfind` は OCaml のサードパーティ製のライブラリを、よしなに管理したり見つけたりしてくれるコマンドで、[findlib](http://projects.camlcity.org/projects/findlib.html) を使って実装されている。
ただし最近は `OPAM` を使う場合がほとんどなので `ocamlfind` を直接使う機会は少ない。

使い方は以下を公式サイトを参照のこと。

- [OCamlプログラムをコンパイルする](https://ocaml.org/learn/tutorials/compiling_ocaml_projects.ja.html)
- [私の貧弱なOCaml力を晒す 第四回 「findlibと対話」](http://naokirin.hatenablog.com/entry/20120501/1335853423)
- [ocamlfind の公式ドキュメントの個人的まとめ
](https://qiita.com/zenwerk/items/1d1eafcbb45aed3fade7)

## ビルドツール
[ocamlbuild](https://ocaml.org/learn/tutorials/ocamlbuild/), [OMake](https://ocaml.org/learn/tutorials/compiling_with_omake.ja.html), [Oasis](https://ocaml.org/learn/tutorials/setting_up_with_oasis.html) などがあるが、識者の発言を読む限り今後新しくOCamlを書く場合は [Dune(jbuilder)](https://github.com/ocaml/dune) を使えばよさそう。

### Dune （旧 jbuilder）
元々は[JaneStreet](https://opensource.janestreet.com/)というOCamlを使っていることで有名な会社が `jbuilder` という名前で作っていたが、`dune` という名前に変更しOCamlの公式リポジトリ下に移管された。

すでに `Dune` に変更されており `3.x` までリリースされている。
~~リポジトリ名は`dune`だが2018年1月現在はドキュメントの記載やコマンド名は `jbuilder` のまま。
READMEによれば `A full renaming of the documentation and the tool will be done as part of the 1.0 release.` とのことで1.0リリースのタイミングで完全に`dune`になるらしい。~~

使い方は以下を参考にする

- [Quickstart](https://dune.readthedocs.io/en/stable/quick-start.html)
- duneプロジェクトの雛形
    - https://github.com/ifazk/ocaml-scratch
    - https://github.com/lindig/hello
    - https://github.com/Khady/modern-ocaml


## VSCode
[ReasonML](https://reasonml.github.io/) 向けのVSCode拡張がいくつか存在し OCaml もサポートされているが、あくまで ReasonML 向けなので OCaml 向けの拡張を使用するなら [VSCode OCaml Platform](https://marketplace.visualstudio.com/items?itemName=ocamllabs.ocaml-platform) が良い。
作成元が [ocamllabs](https://github.com/ocamllabs/vscode-ocaml-platform) なので継続的な開発も期待できそう。

この拡張は [ocaml-lsp](https://github.com/ocaml/ocaml-lsp) を利用する前提のため、開発で使用する OPAM 環境にインストールしておく。

- https://github.com/ocaml/ocaml-lsp#installation

`ocaml-lsp` は内部で `Merlin` を使用しているため補完などを行うには `.merlin` ファイルが必要だが `dune` でプロジェクトを構築しているなら `dune build` を実行すると `.merlin` が生成されるので、とりあえず `dune build` を実行してみると良い。