きっといろふさんはSML# が書ける
いろふ Advent Calendarも5日目に突入です。
前日は@daiksyさんのirof文が実装できたよ。そう、Scalaならね!でした。
いやー皆さん、面白い記事を書かれますねぇ。いろふさんを 実装したり創造したり世界にしたり文にしたり…ちょっと私には思いつきませんでした。なので、ここは12ヶ月のうち9ヶ月ほど遭遇したよくわからない気合と妄想を駆使して物語を書きたいと思います。
あらかじめ断っておきますがほぼフィクションです。あと言い遅れましたが、タイトルは完全に釣りです。
それは寝ているときにやってくる
とある研究室の一角で、ぺんぎんは気を失ったように眠っていた。机の周りには書籍が散乱しており、目の前に置かれたPCは主の眠りを妨げまいと、静かにスリープモードへ移行している。
このままいけば、ぺんぎんは翌日に目を覚まして「嗚呼、またやってしまったか」などとぼやきつつ、日々の作業にいそしむことだっただろう。
しかしこの日は、少しだけ異なる事象が発生した。
『…ますか…聞こえますか…』
誰かが語りかけてきたのである。
『別世界線の○ろふです…あなたの夢の中で直接語りかけています…』
なぜ時事ネタなのか。なぜ伏字なのか。それ以前に、夢の中で語りかけるとはどういう状況だよと内心思いつつ、尋ねる気力もないぺんぎんは次の言葉を待つ。
『寝ている場合ではありません…SML#で…PFDSを写経するのです…』
どうやらどこかの世界の○ろふさんは、SML#がお好みのようだ。他人にお勧めしてくるあたり、既に自分は写経済みということなのだろう。
さて、このまま無視するという手もある。いくら○ろふさんの言葉とはいえ、こんな時間帯から起きて写経する意味はあるのだろうか。
そこまで考えてから、ふむ、とぺんぎんは肯定する。
おそらく『意味はある』。何よりノリと勢いでここまで生きてきたのだ、謎のパワー駆動というのも悪くない──
スタートはマニュアルから
SML#は日本語のドキュメントがあるので便利だ。
ぺんぎんは基本的にWindowsユーザだ。なので、MinGWのコマンドを叩いていく。"終わらないコンパイル"と呼ばれることもあるSML#のインストールだが、バイナリを利用したインストールはさほど時間のかかるものでもないようだ。
コンソール上をログが軽快に流れていくのを横目に、ぺんぎんは写経対象の本を本棚から取り出す。
"Purely Functional Data Structures"
そういえば、とぺんぎんは検索システムであるつぶやきを探す。発見。
「(赤黒木を)若いうちに一度実装しておくのは非常によい勉強になる。でも、1回でいい。人生は、もっと有意義なことに使うべきだ。」www
そんなことを考えているうちにSML#のインストールが完了した。とりあえずバージョンを確認してみよう。
>smlsharp -v
SML# version 1.2.0 (2012-11-14 18:25:26 JST) for x86-mingw
無事最新版がインストールされたことに、ぺんぎんはひとまず安堵するのだった。
皆大好きStack
夜も更けてきたこともあり、ぺんぎんは今は最初に登場するStackのみ写経することにした。
まず、シグネチャを記述する。
(* stack-sig.sml *) signature Stack = sig type 'a Stack val empty : 'a Stack val isEmpty : 'a Stack -> bool val cons : 'a * 'a Stack -> 'a Stack val head : 'a Stack -> 'a (* raises EMPTY if stack is empty *) val tail : 'a Stack -> 'a Stack (* raises EMPTY if stack is empty *) end
Stackという型、空のStackを生成するempty、Stackの中身が空かどうかを判定するisEmpty、要素とStackをもらって新たなStackを返すcons、Stackがemptyでない場合先頭要素を返すhead、Stackがemptyでない場合先頭以外のデータを含むStackを返すtailが存在することがわかる。
次に、組み込みデータ型のlistを使ったStackの実装を書いてみる。
(* list-stack.sml *) structure List : Stack = struct type 'a Stack = 'a list val empty = [] fun isEmpty s = null s fun cons (x,xs) = x :: xs fun head s = hd s fun tail s = tl s end
もう一つの実装は、custom data typeを使ったものだ。
(* custom-stack.sml *) structure CustomStack : Stack = struct datatype 'a Stack = NIL | CONS of 'a * 'a Stack val empty = NIL fun isEmpty NIL = true | isEmpty _ = false fun cons (x, s) = CONS(x, s) fun head NIL = raise Empty | head (CONS(x, s)) = x fun tail NIL = raise Empty | tail (CONS(x, s)) = s end
ここまでは、SMLとなんら変わらない。まぁ、SML#はSMLの拡張言語なので当たり前の話なのかもしれない。
最後に、インタフェースファイルを記述する。
_require "basis.smi" _require "stack-sig.sml" structure Stack = struct type 'a Stack (= boxed) val empty : 'a Stack val isEmpty : 'a Stack -> bool val cons : 'a * 'a Stack -> 'a Stack val head : 'a Stack -> 'a val tail : 'a Stack -> 'a Stack end
ぺんぎんは、テストがないから自信ないな、とぼやくのであった。
夜明け
日が昇り始めたのを確認したぺんぎんは、急いで対話環境を立ち上げて簡単な動作確認をすることにした。
>smlsharp
#use "stack-sig.sml";
#use "list-stack.sml";
#List.head(List.cons(1,List.empty));
val it = 1 : int
#use "custom-stack.sml";
#CustomStack.head(CustomStack.cons(1,CustomStack.empty));
val it = 1 : int
とりあえずは動作しているようだ。ひとまず安堵。
次は分割コンパイルや残りの写経を頑張ろうと決意しつつ、日常に戻るぺんぎんであった──