お気楽 Standard ML of New Jersey プログラミング入門と Yet Another SML/NJ Problems のフォントを Web フォント (Noto Sans JP, Noto Sans Mono) に変更し、印刷用の CSS を追加しました。Web ブラウザの印刷機能を使って PDF に変換することもできます。表示が崩れるときはフォント Noto Sans Mono CJK JP をインストールしてください。
Standard ML of New Jersey (SML/NJ) は ML (Meta Language) という関数型プログラミング言語の一つです。ML は 1970 年代後半にエジンバラ大学で定理証明を行うシステム Edinburgh LCF を記述するため、R. Minler 博士を中心に開発された言語です。その後、改良が重ねられ、いくつかの ML 処理系が作られました。SML/NJ はその一つで、AT&T の MacQueen 氏と Princeton 大学の Appel 氏によって作成された実用的な ML 処理系です。
関数型言語というと、昔は Lisp (Common Lisp, Scheme) が有名でした。Lisp の場合、データに型はありますが、変数に型はありません。これに対し ML は強く型づけされた言語で、コンパイル時に静的な型チェックを行うことで、多くのエラーを検出することができます。
ML で一番有名な機能は「型推論」でしょう。ML はプログラムから変数などのデータ型を見つけてくれるので、プログラマが型を宣言する必要はほとんどありません。推論できない場合にかぎり、ML は型宣言を要求します。この機能により、ML は静的な型チェックを行う「型付きの言語」でありながら、 Lisp のような柔軟なプログラミングが可能になっています。この他にも、パターンマッチング、多相型関数、モジュール・システムなど、ML には興味深い機能がたくさんあります。
ML は様々な実装がありますが、本稿では SML/NJ を使って簡単なプログラムを作りながら ML を勉強をしていきたいと思っております。まあ、初心者が作るプログラムなので、ML らしい綺麗なプログラムは書けないと思います。間違いやお気づきの点がありましたらご指摘いただけると助かります。たいしたことはできませんが、よろしければお付き合いくださいませ。
SML/NJ は次のサイトからダウンロードできます。
Windows の場合、バイナリが用意されているので、とても簡単にインストールすることができます。ただし、Windows 10 で動作する SML/NJ は 32 bit 処理系だけです。また、Unix 系 OS の場合、ソースからインストールすることも簡単です。
上記ページにしたがってファイルをダウンロードし、スクリプトファイルを実行するだけです。なお、ソースをコンパイルするのに gcc と g++ が必要になるので、あらかじめインストールしておいてください。
最後に、パスを通すことをお忘れなく。たとえば、ディレクトリ ~/sml に SML/NJ をインストールしたならば、次のコマンドを実行します。
$ export PATH=$PATH:$HOME/sml/bin
あなたがシェルに bash を使っているのであれば、このコマンドをホームディレクトリのファイル .bashrc に追加しておくといいでしょう。
Windows 10 や Unix 系 OS の場合、シェルでコマンド sml を実行すると、対話モード (interactive mode) で SML/NJ を起動することができます。
$ sml Standard ML of New Jersey (64-bit) v110.98 [built: ...] -
- は SML/NJ のプロンプトです。Windows の場合、Ctrl-Z (Ctrl キーを押しながら z を押す) を入力してリターンキーを押すと終了します。Unix 系 OS の場合、Ctrl-D を入力すると終了します。プロンプトのあとに式を入力すると、SML/NJ は式を評価して結果を返します。
SML/NJ の場合、プログラムを入力すると自動的にコンパイルされます。対話モードの場合、use "ファイル名"; と入力すると、ファイルをロードしてプログラムがコンパイルされます。SML/NJ を実行するときに、"$ sml ファイル名" のようにコマンドラインからファイル名を入力してもかまいません。
なお、Unix 系 OS の場合、sml の対話モードにはコマンドラインの編集やコマンド履歴をたどる機能がありません。この場合、rlwrap をインストールすると便利になります。
sudo apt install rlwrap
あとはシェルで rlwrap ocaml を実行するだけです。簡単なプログラムであれば、これだけでもかなり便利になります。
SML/NJ はプログラムをネイティブコードにコンパイルして実行するので、バイトコードにコンパイルする処理系よりもプログラムを高速に実行することができます。その実行速度ですが、たらいまわし関数を使って調べてみました。
リスト:たらいまわし関数 (SML/NJ) fun tak(x, y, z) = if x <= y then z else tak(tak(x - 1, y, z), tak(y - 1, z, x), tak(z - 1, x, y)) (* 時間計測用 *) fun tak_exec(x, y, z) = let val a = Timer.startRealTimer() in tak(x, y, z); Timer.checkRealTimer( a ) end
それでは実行結果を示します。tak(22, 11, 0) を計算しました。使用した SML/NJ のバージョンは 110.98 です。
処理系 | 秒 |
---|---|
Python (ver 3.10.12) | 62.23 |
Ruby (ver 3.0.2p107) | 25.59 |
Lua (ver 5.4.4) | 22.41 |
Gauche (ver 0.9.15) | 21.29 |
ocamlc (ver 4.13.1) | 9.46 |
SBCL (ver 2.1.11) | 4.90 |
SML/NJ (ver 110.98) | 2.32 |
Julia (ver 1.10.5) | 1.84 |
SBCL (最適化) | 1.50 |
GCC -O2 (ver 11.4.0) | 1.19 |
ocamlopt (ver 4.13.1) | 1.05 |
SML/NJ は SBCL (Common Lisp) より速い結果になりましたが、Julia, GCC, OCaml にはかないませんでした。ただし、SBCL は最適化オプションを指定すると SML/NJ よりも速くなります。最適化オプションを指定したプログラムは拙作のページ Common Lisp Programming をお読みください。興味のある方は、ほかのプログラムでも試してみてください。
『お気楽 Standard ML of New Jersey 入門』の著作権は筆者「広井誠 (Makoto Hiroi)」が保持します。無断使用や無断転載は禁止いたします。お気楽 Standard ML of New Jersey 入門で作成したプログラムはフリーソフトウェアとします。ご自由にお使いください。プログラムの改造や配布もご自由にどうぞ。その際は、出典を明記してくださるようお願いいたします。
ただし、これらのプログラムは無保証であり、使用したことにより生じた損害について、作者「広井誠 (Makoto Hiroi)」は一切の責任を負いません。また、これらのプログラムを販売することで利益を得るといった商行為は禁止いたします。