S式で書くOCaml
更新履歴:
- 2013年4月6日、更新版
REPL追加、リーダーマクロ等追加、common.scmに色々追加
- 2012年4月8日、初版公開
S式でOCamlを書けたらLispマクロでメタプログラミングできたりして良さそうだな
という所が出発点でありゴールです。
(一応S式でOCamlを書こうという試みは過去にもあったようですが、マクロまで踏み込んではいなかったようです)
実行にはOCaml処理系と、Scheme処理系Gaucheが必要です。
OCaml website
Gauche website
以下が変換スクリプト本体、マクロサンプル集です。
s_exp_ocaml.scm (変換スクリプト)
common.scm (共通ライブラリ、これ自体がマクロのサンプルも兼ねてます)
src.scm (単純な例)
使い方は単純で変換スクリプト「s_exp_ocaml.scm」に引数としてソースのファイルを与えると
標準出力に変換されたOCamlのコードを出力します。
(変換スクリプトの実行にはGaucheが必要です)
gosh s_exp_ocaml.scm src.scm > result.ml
ocamlc result.ml
もっともらしい概要のようなもの
基本的にLisp(Scheme)を目指しているわけではなく、
単純にOCamlのコードをS式に落とし込むことを中間目標とします。
これによりLispマクロを導入するにあたって最大の障壁である文法の問題を解決します。
そしてOCamlの機能を基礎として、最終目標はそこからの拡張を目指します。
(OCamlに無い機能は言語コアには組み込まず、原則としてマクロで拡張する方針です)
以下が組み込みとして持つOCamlの機能、特徴(の一部)
- レキシカルスコープ、高階関数
- 静的型付け、型推論
- パターンマッチ
- カリー化、関数の部分適用
- オブジェクト指向プログラミング
- 例外処理
この辺はOCamlの機能に丸投げです、OCamlは素晴らしい。
以下が組み込みとして持つOCamlに無い機能
- Scheme R5RSマクロ(define-syntax, syntax-rules)
- Common Lispマクロ(define-macro)
- リーダーマクロ(set-macro-character等)
以下が組み込みではなくマクロで拡張された機能、マクロのサンプルも兼ねています
(以下のマクロは全てcommon.scmで定義されている)
- リストの内包表記(HaskellやPython等の言語が持つ機能、組み込みのリストを扱う)
マクロ名は「list-ec」
- 関数の合成(Haskell等の言語が持つ機能)
マクロ名は「compose」
- 可変長引数の関数(記法はSchemeから導入、厳密には関数ではなくマクロを定義するマクロ)
マクロ名は「defun-varargs」
(defun-varargs foo args exp) や (defun-varargs foo (v1 v2 . opts) exp)と書けば引数がリストにまとめられます。
- 契約プログラミング(EiffelやDの持つ機能)
マクロ名は「contract-fun」
各種機能に関する情報等
REPLを起動してみる
REPLはS式OCamlの入力を受け付け、OCamlコードに変換するフロントエンドと
変換されたOCamlコードを受け取って結果を返すバックエンドのocaml toplevelで
構成されます。
以下のコマンドで起動します
#rlwrap gosh s_exp_ocaml.scm
rlwrapは必須ではありませんが、あった方が便利です。
*** S-expression OCaml version 0.20130406
*** OCaml version 4.00.1
#
REPLが起動したら、入力待ちの状態になります。
式を入力してみましょう。
# (* 4 -5)
((4) * (-5));;
- : int = -20
「(* 4 -5)」と入力したところ、「((4) * (-5));;」へと変換され、
バックエンドのOCamlインタプリタに渡されます。
そして「- : int = -20」というのがOCamlが評価した結果となります。
リストは「'(exp1 exp2 ...)」或いは「(list exp1 exp2 ...)」です。
(詳細は「基本的なデータ、文法等」)
# '(1 2 3 4 5)
([(1);(2);(3);(4);(5)]);;
- : int list = [1; 2; 3; 4; 5]
「Ctrl + D」か、或いは「(exit 0)」でREPLを終了します。
もう少しREPLについて補足
以前日記に書いた古い情報
すでに古い情報になっていて、現在のバージョンとは仕様が所々異なります
S式OCaml(Lisp風OCaml)トランスレータ
S式OCaml(Lisp風OCaml)トランスレータ2
S式OCaml(Lisp風OCaml)トランスレータ3
図形描画を行うサンプル
結果はGDを利用してファイルに出力されます(png形式)
GDインターフェースにはgd4oを利用しています。
同じディレクトリに「gd.cma」「dllocamlgd.so」がある場合は以下のようにコンパイル、及び実行を行います。
gosh s_exp_ocaml.scm draw3.scm > result.ml
ocamlc -dllpath . gd.cma result.ml
./a.out
draw1.scm コード
draw1.scm 実行結果
単純な四角形を出力するだけです
draw2.scm コード
draw2.scm 実行結果
シェルピンスキーのギャスケットを出力します
draw3.scm コード
draw3.scm 実行結果
波紋のような図形を出力します
draw4.scm コード
draw4.scm 実行結果
ドット絵を出力します