日本ソフトウェア科学会第 39 回大会 (2022 年度) 講演論文集

言語要素の選択と組合せが可能な関数型言語処理系生成フレームワーク
岡本 憲汰

岩崎 英哉

寺田 実

プログラミング言語における評価戦略，スコープ規則等の言語要素の特徴を理解するには，異なる言語要素を持つプログラミング言語でプログラムを記述，実行して結果を比較することが有効である．しかし，言語の構文など，注目する言語要素以外の部分が異なる言語処理系を用いると，処理系の土台が異なるため，公平な比較が難しい．この問題を解決するため，本発表では，言語要素をモジュール化して提供し，注目する言語要素だけが異なり他は共通な複数の関数型言語処理系を生成可能なフレームワークを提案して実装した．本実装では，評価戦略として値呼び，名前呼び，必要呼びの 3 種類，スコープ規則として，静的スコープ，動的スコープの 2 種類のモジュールを提供し，言語要素の異なる 6 種類の処理系を生成することができる．の特徴を把握し，処理の違いを正確に理解すること

1 はじめには，コンピュータサイエンスにおける基本的な概念の関数型言語は，関数を定義し，関数に実引数を与え理解につながるだけでなく，目的に適したプログラミる関数適用の組み合わせとしてプログラムを記述するング言語の選択なども可能とする．

プログラミング言語である．代表的な関数型言語には，言語要素を理解する手段のひとつとして，プログML [6]，Scheme [1]，Haskell [2]，Emacs Lisp [3] 等がラムを異なる言語要素を持つ別々の言語で記述，実行挙げられる．

し，結果を比べる方法が考えられる．しかし，この方それぞれの関数型言語は構成する言語要素が異な法は，構文を始めとして，比較対象である言語要素以る．本稿において言語要素とは，評価戦略，スコープ外の部分も基本的に異なるため，同一内容のプログラ規則など，プログラムのふるまいを定める，各プロムを二重に記述する手間がかかる上に，注目する言語グラミング言語が規定している事柄のことを指すも要素だけを純粋に比較することが難しい．のとする．たとえば Haskell と Scheme では，評価戦例えば，Haskell と Scheme を用いて評価戦略の違略が遅延評価と先行評価といった違いがある．また，いによる性能の差を評価しようと考えた場合，それぞScheme と Emacs Lisp では，スコープ規則が静的ス

れの構文に沿ったプログラムを記述する必要がある．

コープと動的スコープといった違いがある．言語要素

さらに，そもそも処理系の内部構成が異なるので公平に比較できるとは言い難い．

A functional language processor generation framework that allows selection and combination of language elements
Kenta Okamoto, 電気通信大学大学院情報理工学研究科,Dept. of Information and Computer Science, The
University of Electro-Communications.
Hideya Iwasaki, 明治大学大学院理工学研究科 情報科学専攻, Dept. of Computer Science, Meiji University.
Terada Minoru, 電気通信大学大学院情報理工学研究科,Dept. of Information and Computer Science, The
University of Electro-Communications.

これに対して，比較対象の言語要素のみが異なり，他は同じ言語処理系を用意できれば，比較対象の言語要素以外には相違がない公平な比較を行うことができる．さらに，複数の言語要素の組合せを比較したい
場合であっても，組み合せる要素以外が等しい言語処理系を用意できればよい．この手法を利用するためには，多数の言語要素の組み合せごとに，言語処理系を容易に構築できる必要がある．

本研究では，Scheme 処理系 [7] を参考とした小さ

正格な評価方法は，サンクの管理が必要ないため，な処理系を土台として，言語要素を選択し組み合せる実装が簡単であるという利点があるが，値を必要としことで，注目する言語要素の部分だけが異なるようなない可能性がある引数を必ず評価するという欠点が関数型言語処理系を生成するフレームワークを提案ある．非正格な評価方法は，引数の評価を保留するこして実装する．とにより，値が必要でない引数を評価しない，すなわ

本フレームワークでは，言語要素をモジュールとち無駄な計算をしないという利点があるが，保留したすることで言語要素の選択を可能とする． モジュー

引数のデータをサンクを用いて管理する必要がある

ルとして提供する言語要素は評価戦略とスコープ規ため，処理が複雑になるという欠点を持つ．

則の 2 つである．評価戦略については値呼び，名前2 つの評価方法の違いを考えるために，Scheme の呼び，必要呼びの 3 種類を，スコープ規則について構文を用いて次のような式を例に挙げる．

は静的スコープと動的スコープの 2 種類を提供する．

((lambda (x y) (+ 1 y))(+ 1 2) (+ 3 4))

本フレームワークを利用することにより，対象の言語要素を選択，指定するだけで言語要素の異なる 6 種類の処理系を生成できる．
本研究の最終的な目的は言語要素等の基礎的な概これは引数 x，y を受け取って y に 1 を加えるラムダ式で表された関数に，(+ 1 2)，(+ 3 4) という式を実引数として与える関数適用式である．

念の学習環境への応用であり，本フレームワークはそ正格な評価においてこの式を評価する場合，まず実の基本部分をなす．目標とする学習環境は，フレーム引数である (+ 1 2)，(+ 3 4) を評価し，結果の値ワークによって生成された言語要素の異なる言語処

3，7 を関数であるラムダ式に渡す．ラムダ式では，x理系を並べ，同じプログラムを用いた結果の比較や，には 3，y には 7 を束縛するため，最終的に (+ 1 7)

ステップ実行や構文木の可視化，変数の追跡などを用を評価し，値 8 が得られる．非正格な評価では，実引いた比較をすることで，言語要素の特徴を理解できる数 (+ 1 2)，(+ 3 4) を遅延し，それらを関数に渡ようにするものである．また，学習環境としてプログす．評価される式は (+ 1 (+ 3 4)) という形になり，ラミングが容易にできるようなシステム，例えば入力

このとき，(+ 3 4) を強制する．最終的には (+ 1 7)

補完等の入力支援機能や，理解が容易なエラー表示なと，正格な評価と同様な結果を示す．２つの評価は，ども用意したいと考えている．

(+ 1 2) が評価されるか否かという点が異なる．
2. 1. 1 値呼び，名前呼び，必要呼び2 言語要素

正格な評価は値呼び (call by value) とも呼ばれる．

2. 1 評価戦略

一方非正格評価には名前呼び (call by name) と必要

評価戦略は，式の評価方法である．大きく分けると呼び (call by need) がある．名前呼びと必要呼びは次

正格な評価 (strict) と非正格な評価 (non-strct) に分かれる．正格な評価では，関数適用式の実引数の評価を式を評価する前に行う．一方，非正格な評価では，このような実引数の式の評価を保留し，その式の結果が真に必要になった場合にのみ評価を行う．
非正格評価において，評価を保留することを遅延のように異なる．
名前呼び 評価を遅延された式が，その結果が必要になるたびに評価される．
必要呼び 評価を遅延された式が，その結果が必要になった時に評価されれば，その評価結果を再利用し，同じ引数を重複して評価しない．と呼び，評価を遅延した式を評価し値を求めること

2. 1. 2 非正格評価における値の形式を強制と呼ぶ．このような式の遅延と強制は，サンク非正格評価後の値は，弱頭部正規形 (Weak Head(Thunk) という評価を保留した式とその時の環境をNormal Form，WHNF) の形式を取る．サンクは必まとめた処理系内部のデータ構造を用いることで実要となった時点で強制されるが，強制で得られた値現できる．の中にはデータが含まれる場合がある．WHNF は，値内部にサンクが残っているような形式である．一して提供する．これにより，6 通りの処理系を生成で方，頭部正規形 (Head Normal Form，HNF) は値内きるようになる．

部のサンクがすべて強制された形式である．Haskell

さらに，非正格な評価においては，結果の値を表の Read-Eval-Print Loop (REPL) である GHCi で示する形式を WHNF と HNF から選択できるようには，評価結果の値の出力時に WHNF 内部のサンクをし，これもモジュールとして提供する．WHNF におすべて強制し，HNF となるようにしている．

いて，サンクを出力する場合は「#Thunk{遅延された式}」のように表示する．値の表示形式が異なる場合

2. 2 スコープ規則も別の処理系であるとした場合，10 通りの処理系がスコープ規則は，変数の参照方法に関する言語要素生成できることになる．

である．静的スコープと動的スコープがあり，前者はその変数が記述される場所で参照できる変数を参照

3. 2 GUI の利用するもの，後者はその変数が実際に評価された場所で最終的な学習環境への応用を考え，本フレームワー参照できる変数を参照するものである．

クは GUI 上で動作するようにする．GUI の見た目を静的スコープは，クロージャ(closure) という関数

図 2 に示す．これは入力のテキストエリア，出力のテと関数生成時の環境を組み合わせたデータ構造を用

キストエリア，実行用ボタン，モジュール選択用のトいて実現できる．クロージャはラムダ式によって作らグルボタンで構成されている．入力のテキストエリア

れた値としての関数を表す形式である．にプログラムの記述を行い，モジュール選択用のトグ両者の評価方法の違いを考えるために，Scheme のルボタンでモジュールの選択を行う．

構文を用いて次のような式を例に挙げる．

(let((f (let ((a 5))(lambda (x) (+ x a)))))(let ((a 1)) (f 100)))
これは，変数 f に，変数 a に 5 が束縛された環境において生成した関数 (lambda (x) (+ x a)) のクロー

4 実装
4. 1 処理系の土台処理系は，Scheme インタプリタ JAKLD [7] を参考にした小さな (Scheme のサブセットである) 処理系を用いる．これは，次のようなものである．

• 特殊形式は lambda，if，define，quote，let，ジャを束縛し，その後，変数 a に 1 が束縛された環

and，or のみ．

境において (f 100) を評価する．静的スコープにお• 引数は固定個のみ．

ける (f 100) の評価は，記述された環境で参照でき• 必要最低限の組込関数．

る a の値 5 を用いて値 105 が得られる．一方動的ス

実装には Java を用いる．また，処理系は入力されコープでは，実際に評価された環境における a の値 1た式をそのまま解釈実行するインタプリタの方式をを用いて値 101 が得られる．

取る．

3 フレームワークの仕様

処理系内部のデータはクラスによって表現し，Int，Charactar，Boolean，Double．String，Function，

3. 1 言語要素の選択

Pair，List がある．データ型の Int，Charactar，本フレームワークのイメージを図 1 に示す．

Boolean，Double，String は Java のデータ型をそ

本フレームワークでは，先に述べた評価戦略とスのまま用いる．Function は組込関数 Subr かユーザ

コープ規則という２つの言語要素をモジュール化す定義関数 Lambda のいずれかである．組込関数は Javaる．評価戦略では，値呼び，名前呼び，必要呼びの 3で処理が定義されており，ユーザ定義関数は変数と種類をモジュールとして提供し，スコープ規則では静式，環境がまとめられたクロージャとなる．Pair は的スコープと動的スコープの 2 種類をモジュールとコンスセルであり，フィールドに car 部と cdr 部を図 1: 本フレームワークのイメージ

図 2: 本フレームワークで利用する GUI
持つ．List は空リストをペアと同等に扱うものであジュールも 2 種類用意する．スコープ規則についてり，空リストの car 部と cdr 部はそれぞれ空リスト

は，静的スコープ及び動的スコープについての 2 種自身を参照する．このような処理系内部のクラス構成類のモジュールを用意する．

は JAKLD のそれをそのまま踏襲している．

モジュールのクラス構造を図 3 に示す．モジュールはそれぞれ 1 つのクラスとして扱う．評価戦略に関する

4. 2 言語要素のモジュール化

クラスは値呼びのクラス EvalModule callbyvalue，

4. 2. 1 モジュールの構成

名前呼びのクラス EvalModule callbyname，必要呼評価戦略モジュールは，値呼び，名前呼び，必要呼びのクラス EvalModule callbyneed である．非正格びの 3 種類を用意する．また，非正格評価では，最終な評価である名前呼び，必要呼びは処理が共通する的な値の形式を WHNF か HNF とするか選択するモ部分が多いため，抽象クラス EvalModule nonstrict図 3: モジュールのクラス構造に共通部分をまとめそこから継承する．また値のライトされた 2 行目及び 7 行目が Eval.eval もしく

出力形式に関して，正格評価における値の出力には Thunk.delay となっている部分のみである．つま関するクラ スが IOModule，WHNF の値を表示 すり，この部分の処理のみ評価戦略ごとに異なるようにるクラスが IOModule WHNF，WHNF を HNF までモジュール化すれば良い．

強制して表示するクラス IOModule HNF である．ス

実装では，差分となる部分を新たなメソッドとし，コープ規則に関するクラスは，静的スコープのクメソッドをまとめたクラスをモジュールとすることでラス ScopeModule static と動的スコープのクラス実現する．図 5(a)，(b) にモジュール化された引数評

ScopeModule dynamic である．

価のコードを，(c) は図 4 の差分をまとめたモジュー

選択した各モジュールは，クラス Module のイン

ルの呼び出し元のコードを示す．

スタンス変数として格納し，Module を通してモジ処理系内部で言語要素によって異なる処理が必要

ュー ル の メ ソッド を 呼 び 出 す．た と え ば ，WHNFな部分で，モジュールを格納しているインスタンスで表示を行う名前呼びで静的スコープの処理系をmodules のメソッド EvalModule によりモジュールの利 用 し た い 場 合 は ，ク ラ ス Module の イ ン ス タ ン

インスタンスを得て，モジュールのメソッドを呼び

ス変数に EvalModule callbyname，IOModule WHNF，出す．

ScopeModule Dynamic それぞれのインスタンスを格

4. 2. 3 評価戦略ごとの差分納する．引数の評価や環境の参照など，これらが必要

本処理系において，評価戦略ごとに処理が異なる部な場面で必要なインスタンスメソッドを呼び出す．

分は次の通りである．

4. 2. 2 モジュール化の方法• 実引数の評価

言語要素のモジュールは，処理系内部において言語• 変数の束縛 (let, define)

要素ごとに処理が異なる部分をそれぞれのモジュール• サンクの場合に強制する箇所

に関するクラスにまとめることで実装した．

引数の評価，変数の束縛は名前呼び，必要呼びでの具体的な例として，関数適用式における実引数の処処理が同様であるのでまとめて考える．

理に関するモジュール化前のソースコードの一部を図

実引数の評価は図 5 で示した通りである．ただし，4 に示す．なお実際のプログラムでは，非正格評価に非正格な評価での引数の評価において，実際はすぐ評おいてもすぐに評価される引数については遅延する

価される引数については即時評価している．この引必要がないため，即時評価されるようにしているが，数を即時評価するか否かは，関数ごとに内部で決め

ここでは簡単のため省略した．ている．組込関数のほとんどは引数をすぐ利用する

図 4 において，(a) と (b) のコードの違いは，ハイため即時評価する．引数を即時評価しないものには，その結果を出力する．
12
34567Pair args = new Pair(Eval.eval(list.car, env),List.nil);
Pair last = args;
while ((list = (List) list.cdr) !=List.nil) {Pair x = new Pair(
Eval.eval(list.car, env),List.nil);last.cdr = x;last = x;891011}4. 2. 4 スコープ規則ごとの差分本処理系において，スコープ規則ごとに処理が異なる部分はクロージャに引数を与えて関数適用を行う部分である．静的スコープではクロージャ生成時の環境を利用する．一方，動的スコープでは関数適用を行う環境を利用して評価する．

4. 3 処理系の生成
本処理系は，1 つのインスタンスとして生成する．
処理系をメインの処理とせずに 1 つのインスタンス(a) 正格な評価とする理由は，今後複数の処理系を GUI 上で並べて同時実行し，比較できるようにするためである．実際

12
3
4
567

Pair args = new Pair(Thunk.delay(list.car, env),List.nil);
Pair last = args;
while ((list = (List) list.cdr) !=List.nil) {Pair x = new Pair(
Thunk.delay(list.car, env),List.nil);last.cdr = x;last = x;891011}には，入力部と出力部，選択するモジュールを用いて処理系のインスタンスを生成し，指定した入力部からの入力を処理系が評価し，結果を指定した出力部に出力する．

5 実際の実行例
5. 1 処理系ごとに異なる動作をするプログラム
本フレームワークを用いて実際に実行した結果を示す．まず， 6 通りの処理系が比較できる例として以下のプログラムを用いる．

(b) 非正格な評価

図 4: 正格な評価と非正格な評価における引数評価のソースコード比較(define plusxxaa(let ((a (displayln 20)))3(lambda (x) (+ x (+ x (+ a a))))))

1
2

4(let ((a (displayln 10))(b (displayln 40)))7(plusxxaa (displayln 50)))5

ユーザ定義関数や組込関数 cons が挙げられる．
変数の束縛については，正格な評価では環境に変数名と束縛する値の対応を格納し，非正格な評価では環境に変数名とサンクの対応を格納する．サンクの場合

6displayln という関数は，結果を出力して改行を行う独自に定義した組込関数である．に強制する箇所は，名前呼びではサンクに格納されてまず，a に 20 を束縛した局所的な環境において，いる式を格納されている環境において評価して結果をplusxxaa という x を引数にとって x + x + a + a返す．必要呼びではサンクに格納されている式を評価を返す関数を定義する．その後局所的な変数としてした後に，サンクを結果の値に破壊的に置き換える．

a，b を定義し，plusxxaa を呼び出す．

また非正格な評価における結果の形式を WHNF にするか，HNF にするか選択できる部分のモジュールについて，処理が異なる部分は結果出力時にサンクが現れた場合である．WHNF では，#Thunk{遅延された式}と表示する．一方 HNF では，サンクを強制し，5. 1. 1 値呼び，静的スコープ値呼び，静的スコープのモジュールを選択し，実行した結果は次のようになる．なお，plusxxaa という出力は定義時に返される結果である．

1class EvalModule_callbyvalue implements
EvalModule {1class EvalModule_nonstrict implements
EvalModule {

2...

2...

public Object
evalArg(Object o, Env env) {return Eval.eval(o, env);

345}
7 ...
8 }

345

public Object
evalArg(Object o, Env env) {return Thunk.delay(o, env);

}
...
8 }

667(a) 正格な評価のモジュール(b) 非正格な評価のモジュール

1

Pair args = new Pair( modules.EvalModule().evalArg(list.car, env) , List.nil);

2

Pair last = args;
while ((list = (List) list.cdr) != List.nil) {Pair x = new Pair( modules.EvalModule().evalArg(list.car, env) , List.nil);34

last.cdr = x;last = x;567}(c) モジュールの呼び出し元

図 5: 引数評価をモジュール化したソースコード

20
plusxxaa

10405014050120
束縛時や関数適用時は，値呼び，静的スコープと処理が同じである．(plusxxaa) 内の評価では，a は関数呼出し元の環境より 10 となる．したがって結果とし

まず，plusxxaa の局所的環境における a への値のて，(+ 50 (+ 50 (+ 10 10))) が評価され，120 が束縛時に (displayln 20) が評価されている．その返される．

後，6 行目の let おいて，a，b への値の束縛時に5. 1. 3 名前呼び，静的スコープ(displayln 10)，(displayln 40) がそれぞれ評価

名前呼び，静的スコープのモジュールを選択し，実され，その環境内で式の評価が行われるが，関数適用行した結果は次のようになる．なお，出力時の値の形

時に引数の (displayln 50) が評価されている．

式は HNF となるようにしている．

(plusxxaa) 内の評価では，a は記述された場所の環境より 20 となる．したがって結果として，(+ 50(+ 50 (+ 20 20))) が評価され，140 が返される．
5. 1. 2 値呼び，動的スコープ値呼び，動的スコープのモジュールを選択し，実行した結果は次のようになる．

20
plusxxaa

1040

plusxxaa

50502020
140
値呼びの時とは異なり，名前呼びでは，plusxxaaの局所的環境における a の束縛時に (displayln 20)が評価されておらず，6 行目の let 内での a，b の束縛時にも評価がなされておらず，遅延されていることがわかる．しかし，その後は (displayln 50) と
表 1: たらい回し関数の実行時間(displayln 20) がそれぞれ 2 回ずつ出力されている．これより plusxxaa の評価時に，評価が遅延され値呼び

名前呼び

必要呼び

た引数の x，呼び出し元の環境の a がそれぞれ 2 回ず

3219.397 ms

1.09 ms

0.41 ms

つ必要になり，その度に評価がなされていることがわかる．

使っていることがわかる．

5. 1. 4 名前呼び，動的スコープ
名前呼び，動的スコープのモジュールを選択し，実行した結果は次のようになる．
plusxxaa

5050
1010120
束縛時や関数適用時は，名前呼び，静的スコープ

5. 2 たらい回し関数のプログラム
次のたらい回し関数 [5] を用いて，評価戦略ごとに実行時間を比較する例を示す．

(define (tarai x y z)
(if (not (< y x)) y3(tarai (tarai (- x 1) y z)4(tarai (- y 1) z x)
5(tarai (- z 1) x y))))1267(tarai 12 6 0)と処理が同じである．しかし，plusxxaa 内の評価は，a の関数呼び出し元の環境より 10 となり，これを用

これは，再帰的にたらい回し関数を呼ぶプログラ

いて評価がなされたことがわかる．

ムである．3 行目から 5 行目にかけて，たらい回しの5. 1. 5 必要呼び，静的スコープ関数が入れ子になっている．このプログラムは，2 行

必要呼び，静的スコープのモジュールを選択し，実目の条件分岐において，(not (< y x)) が true で行した結果は次のようになる．
plusxxaa

5020120あれば，x，y の値は必要であるが，z の値は不要である．値呼びでは，関数適用時に z を評価するため，2 行目で終わった場合に無駄に評価が必要になる．一
方名前呼び，必要呼びでは 2 行目の条件分岐で終了すれば，z は評価されることはない．

束縛時や関数適用時は，名前呼び同様に評価がされこのプログラムの実行時間を測定した結果を表 1 にず遅延されていることがわかる．しかし，plusxxaa示す．なお，時間は Java の System.nanotime() をの評価時には (displayln 50) と (displayln 20)用いた時間測定用の特殊形式を用意して測定し，10がそれぞれ 1 回のみしか出力されていない．これに回分の平均を取った．

より，必要になるたびに評価されているのではないということがわかる．

このように，プログラムによっては評価戦略ごとに実行時間が大きく変化することもわかる．

5. 1. 6 必要呼び，動的スコープ
必要呼び，動的スコープのモジュールを選択し，用いた結果は次のようになる．
plusxxaa

50
10120

6 おわりに
6. 1 まとめ
本研究では，言語要素のような基礎的な概念の学習環境の作成に向け，モジュールを選択して組み合せる関数言語処理系を生成するフレームワークを実装した．また，このフレームワークを利用するため，必要束縛時や関数適用時は，必要呼び，静的スコープ最低限の機能を有するような小さい処理系を作成しの部分と同じであるが，a は関数呼び出し元の環境をた．言語要素のモジュールについては，言語要素の差分となる部分をまとめ，ひとつのクラスとすることで実現した．

今後は，まずステップ実行の実装を行い，その他学習環境において必要であると考えている機能を追加し実際にこのフレームワークを利用することで，言語ていきたいと考えている．現状考えている機能は，入要素の組み合わせが異なる 6 種類の関数言語処理系

力補完等の支援や，エラー箇所のハイライト，変数のを生成したり，評価戦略ごとの実行時間の比較をおこ追跡等が挙げられる． ステップ実行に関しては，代なったりすることができた．

数ステッパ [4] を用いて式を変形していくことで，視覚的に理解しやすい実装にしていきたい．

6. 2 学習環境への応用に向けて
現状のフレームワークは，言語要素を選択し，入力部にプログラムを入力し，結果を出力部に出すという基本的な機構のみが実装されている．この機構のみだと，結果から言語要素の特徴を捉えることしかできず，学習環境としては不十分である．例えば，5.1 節
で用いたプログラムは，実際に評価されていることを確認するために displayln 関数をプログラム中に入れることで評価戦略の振る舞いなどを比較したが，本来はこのようなものをプログラム中に挿入したくなく，また，挿入したとしても出力された値が何を指しているのかは結果だけからだと理解しづらい．
この問題を解決する方法には，プログラムのステップ実行などが挙げられる．プログラムをステップ実行し，プログラムの途中の式などを可視化することができれば，評価が行われるタイミングなどを理解することができる．

参 考 文 献[1] Abelson, H. and Sussman, G. J.: Structure andinterpretation of computer programs, The MITPress, 1996.
[2] Bird, R.: Introduction to Functional Programming using Haskell – second edition, Prentice HallEurope, 1988.
[3] Chassell, R. J.: Programming in Emacs Lisp: AnIntroduction, Free Software Foundation, Incorporated, 1999.
[4] Clements, J., Flatt, M., and Felleisen, M.: Modeling an algebraic stepper, European symposium onprogramming, Springer, 2001, pp. 320–334.
[5] Gabriel, R. P. et al.: Performance and evaluationof Lisp systems, Vol. 263, MIT press Cambridge,
Mass., 1985.
[6] Milner, R., Tofte, M., Harper, R., and MacQueen,D.: The deﬁnition of standard ML: revised, MITpress, 1997.
[7] 湯淺太一: Java アプリケーション組込み用の Lisp
ドライバ, 情報処理学会論文誌プログラミング (PRO),
Vol. 44, No. SIG04 (PRO17)(2003), pp. 1–16.