sml mlton sml#

JavaScriptとHTML5で群れをシュミレーションしてみよう なんていう楽しい記事を見つけた。

これって、昔factorのサンプルに有ったやつだな。有名なものなのね、初めてしりましたよ。 件の記事にも書かれているけど、(1)群れの中心へ向かおうとする。(2)最低限の距離を取ろうとする。 (3)群れの平均速度ベクトルに合わせようとする。

以前、昆虫が捕食者から身を守る方法として群れを作るってのを知ったけど、同じ原理が 適用出来るんだな。中心は安全、だから中心へ向かおう。最低限の距離がないとお互いが 気まずくなる。そうならないようにしよう。これって、いわゆる 対人距離とか社会的距離 の事だな。そして全体に合わせるってのは、逆に考えると、はみ出し者は狙われる、アウトローは目を 付けられる のだな。

八景島とかの水族館でイルカのショーをよくやってるけど、その中にシンクロナイズド・ スイミングって出し物が有ったはず。これも、鮫とかから狙われないように同じ動作を 同時に行うっていう所から来てるんだろうね。なかなか面白いよ。生物の英知を我々が 取り込んで安泰生活!

sml/nj and mlton

F#から始まって、先祖のocamlで遊んだわけだけど、さらにocamlの先祖へとrootを求めてみる。 すると、polymlとかmoscow-mlとかsml/njとかが出てくる。(FreeBSDのports調べ)

そのうちで一般的に流通してる、sml/njとやらに手を出してみる。smlの前はって言うと、 イギリスの何とかの大学で定理証明のために作られたMLってのがあって、それに色々な 理論を追加して、Standard MLって規格?が生まれたらしい。このあたりは、SchemeのRnRS と同じ流れか。

で、smlnjだけど、ニュージャージィ産なんで、njが付いている。ニューヨークの近くの 州なんかな。Newが付いているって事は、ヨーロッパからの移民が多く住み着いたんで、 Newをつけてんだな。そう言えば、ジャージィー牛の濃厚な乳が懐かしい。

北海道へ行った時に飲んだよ。札幌の近くに広島って町が有ったな。これは広島の人が 移住したんで、故郷を思って付けた地名だろう。

Standard ML of New Jerseyに看板が掲げられている。 どうも、ベル研の敷地内なのかははっきりしないけど、それっぽいな。

FreeBSDではすんなりと入った。関連でX関係が動くという、eXeneってのがあるんだけど コンパイルしようとするとエラー。

この際だから、fedoraの実験棟で実験してみる。sml/njは自前で入れた。config.tgzを 取ってきて、適当なDIR内で展開、後はconfig/install.shって叩くだけで、ネットから 必要なものを勝手に落としてきてコンパイルしてくれる。楽ちん。 ついでに、SML modeってのも 入れておくと吉。

FreeBSDで旨くコンパイル出来なかったeXene、fedoraでも調子悪かった。

[sakae@fedora eXene]$ sh build-eXene
   :
[scanning 930-export.sml]
/home/sakae/SML/bin/sml: Fatal error -- Uncaught exception Io with <unknown> raised at Basis/Implementation/IO/text-io-fn.sml:783.25-783.71

予想外の事が起きたって言われてもねぇ。X系は諦めよう。

smlnjには、コンパイラーが付いているので、実行ファイルを作れるんかな? コンパイル マネージャとかいうMakefileの再発明品を使うと何とかなりそうってのは分かったんだけど どうやるの? 扱う人が少ないせいか、なかなか資料が無い。

かろうじて、 CompileManager(以下CM)はSML/NJに付いてくるmakeシステムです とか 初めてのSMLなんてのを見つけたよ。 どうも、コンパイル結果がヒープに吐き出されるみたい。それをsmlでロードして使う みたいだぞ。調べる範囲を広げてみたら、 SML-NJ, how to compile standalone executable ずばりのやつを質問してる人が居た。仰せの通り試してみると

[sakae@fedora z]$ ml-build test.cm Test.main test-image
Standard ML of New Jersey v110.75 [built: Sat Nov 09 06:57:50 2013]
[scanning test.cm]
/home/sakae/SML/bin/sml: Fatal error -- Uncaught exception Io with <unknown> raised at Basis/Implementation/IO/text-io-fn.sml:783.25-783.71

このエラーは、どこかで見ましたなあ。でも、smlnjに変わるコンパイラ mlton なんてのが 有る事を知った。こちらがその配布場所なんだけど、FreeBSD用なんて 徹底的に無視されてる。(portsにもあったけど、壊れてるマークが付いてた)

Linux用ってのが用意されてるんだけど、Linuxっと言っても広うござんす。fedoraで使えるの? ソースから入れるのが基本でしょってばかりに、コンパイルにチャレンジ。そしたら、 mltonを作るにはmltonが必要ですって再帰してやがんの。さすが、関数型を謳うだけ あって、再帰は当たり前なのね。

しょうがないので、運を天に任せて、バイナリーパッケージで導入。tgzはLinuxで 無宗派の印です(但し、plamoとかslackwareを除く)。その代わり、パッケージ管理の 範囲外になっちゃうけど。。

[sakae@fedora z]$ cat foo.sml
fun main () = print "this is the main function\n"

val foo = 4

val _ = print ((Int.toString 4) ^ "\n")

val _ = main ()
[sakae@fedora z]$ mlton foo.sml
[sakae@fedora z]$ ./foo
4
this is the main function

[sakae@fedora z]$ ldd foo
        linux-gate.so.1 =>  (0xb77ed000)
        libm.so.6 => /lib/libm.so.6 (0x4d5e6000)
        libgmp.so.10 => /lib/sse2/libgmp.so.10 (0x4e56b000)
        libc.so.6 => /lib/libc.so.6 (0x4d402000)
        /lib/ld-linux.so.2 (0x4d3df000)

ちゃんと実行出来たし、生成物には不純物が入ってなさそうだし、良しとするか。ああ、gmp って、やわなLinuxにはひょっとして入っていない?

ここまで、勝手に飛ばしてきたけど、多少の資料をば

初級ML講座

ML演習 The Meta Language

お気楽 Standard ML of New Jersey 入門

Standard ML Programming/Expressions

The Standard ML Basis Library

SML/NJ Error and Warning Messages

smlsharp

上記でいろいろと探っている時、sml#なんてのに出会ったよ。犬も歩けば棒に当たる ですな。 SML#プロジェクトが本拠地らしい。 仙台市片平ったら、広瀬川のほとりのキャンバスだな。おいらが仙台に住んでいた時は、 毎日あの前を通って国分町まで通っていたよ。(決して、バーのバーテンではございません > 仙台に詳しい皆様)

FreeBSDに入るかと思ったら、そんなのサポート外って軽くいなされてしまった。世は猫も 杓子もLinuxなのね。BSD系使いたかったらあぷるにしろってか。しょうがないので、フェドラに 入れた。

smlnj用に入れたsml-modeが使えるかと思ったら、まあ、使えた。

;; sml/ng
(autoload 'sml-mode "sml-mode" "Major mode for editing SML." t)
(autoload 'run-sml "sml-proc" "Run an inferior SML process." t)
(add-to-list 'auto-mode-alist '("\\.\\(sml\\|sig\\)\\'" . sml-mode))
;(setq sml-program-name "/home/sakae/SML/bin/sml")
(setq sml-program-name "/home/sakae/smlsharp/bin/smlsharp")

で、こんなのを

fun sq x:int = x * x ;
val a = (~456) ;
fun i2s i =
    if i < 0 then "-" ^ Int.toString (~i) else Int.toString i ;
print( i2s a ^ " * " ^ i2s a ^ " = " ^ i2s (sq a) ^ "\n" ) ;

emacs上から実行(C-c C-b)してみると

SML# version 1.2.0 (2012-11-14 18:25:26 JST) for x86-linux
# -456 * -456 = 207936
val a = ~456 : int
val i2s = fn : int -> string
val it = () : unit
val sq = fn : int -> int

結果の表示がまちまちになってる。まあ、使えんことはないから、我慢するか。我慢出来ない のは、smlでのマイナスの数値の表し方だったりしますが。。きっと深ーーーい訳が有るんでしょうな。

でも、この評価結果の並びが気になる。途中に挟んでいるemacsで変な事が起こっているの? smlsharpのreplから、use "hoge.sml"しても結果は同じ。一番最初にprintの副作用結果が 出て来る。これって、伊達政宗公のお膝元で開発されたシステムだから? 戦場では一番 大事な結果をまず報告する事が求められるからねぇ。きっとそれに倣ったのだろう。

で、これを、sml#にコンパイルしてバイナリーファイルにするには、

[sakae@fedora z]$ cat hoge.smi

_require "basis.smi"

こんなファイルを用意する。

[sakae@fedora z]$ smlsharp hoge.sml
[sakae@fedora z]$ ./a.out
-456 * -456 = 207936

出来上がったa.outは、ファイルサイズが2.3M有った。stripしたら740kぐらいに小さくなった。 リンクする時に、これでもかって言うぐらい、SMLの標準ライブラリーを取り込んでいるから しょうがないのかな。贅沢は言うまい。そうそう、本家本元のbin/smlsharpもstripされて なくて、30Mぐらいの巨大サイズ。てきぱきと動くようにstripしておこう。10Mを切るサイズに なったよ。

サンプルで遊ぶ

sqlsrverと接続してsqlを投げるなんていう面白そうなのも置いてあるんだけど、そちらには 眼を瞑って、spectrumなんてのを試してみたい。READMEには

Sound Spectrum

This is an example program using FFI.

This program reads raw sound data from standard input by fread(3),
calculates its power spectrum by FFT function of GSL library,
and displays it graphically in real time by using either curses or
OpenGL.

This demo requires the following libraries:

- GNU Scientific Library (libgsl)
- libcurses or OpenGL (libgl, libglu, libglut)

こんな案内が載っていた。どうやら、GSLライブラリィー内のFFTルーチンを呼び出す 表示器らしい。この際だから、OpenGLでやってみる。GSLをまず入れねば。そしてOpenGLの 脇を固める脇役もも

gsl-devel.i686 : Libraries and the header files for GSL development
freeglut-devel.i686 : Freeglut developmental libraries and header files

GLUTによる「手抜き」OpenGL入門 なんてのも有ったぞ。 Makefileを下記のように手直ししておかないと、リンク出来ない。

SMLSHARP = smlsharp
#LIBS = -lgsl -Wl,-framework,OpenGL -Wl,-framework,GLUT  # for Mac OS X
#LIBS = -lgsl -L/usr/X11R6/lib -lgl -lglu -lglut
LIBS = -lgsl -lglut -lGLU -lGL

このサンプルを提供された方は、マカーのようでした。これで、スペアナが動くように なりましたよ。

他にも面白いサンプルが置いてあった。何と手軽に用意されているCライブラリィーを呼び出して しまえる機構が備わっているんだ。この一点でsmlsharpを使う理由になりますよ。

以前CiSE(C In S-Expression)ってのをやった。gaucheのモジュールにCgenってモジュールが あって、それを使ってS式をC語に変換。gccでコンパイルってのだった。 smlsharpのそれは、もう少し簡単に利用出来る。

type c_file = unit ptr

val fopen = _import "fopen" : (string, string) -> c_file
val fclose = _import "fclose" : c_file -> unit

fun fread (dst, len, file) =
    _ffiapply _import "fread"
      (dst : 'a array, _sizeof('a), len : int, file : c_file) : int
  :

Cのライブラリーからfopenとかfreadをimportしてきなさいとな。その型は文字の場合も 有るし、配列とか整数の場合もあるとな。返り値も指定するのね。 対応するC側は、man fopenとか、man freadだな。

       FILE *fopen(const char *path, const char *mode);

       size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

で、使うのは簡単

(* open the file and read the real array from it. *)

val file = fopen ("test.bin", "rb")
val _ = if Pointer.isNull file then raise Fail "fopen failed" else ()

val buf = Array.array (5, 0.0)
val _ = printAry buf

val _ = fread (buf, Array.length buf, file)

val _ = fclose file

val _ = printAry buf

もう、ほとんどC言語を書いている様。