最近の更新 (Recent Changes)

2014-01-01
2013-01-04
2012-12-22
2012-12-15
2012-12-09

Wikiガイド(Guide)

サイドバー (Side Bar)

← 前のページに戻る

デカルト言語で作成するLispインタプリター

Descartes Lisp/λ デカルト言語によるLisp言語の作成 H.Niwa (c) 2010


デカルト言語の例題としてLispを作成しました。

名づけてデカルトLisp/λ(Descartes Lisp/λ)です。


恒例ですので、まず、"hello, world"を次に示しましょう。


(print "hello, world")

このデカルトLisp/λを使うとlispの関数とともに、λ式(みたいなもの)が 書けます。


(car '(a b c))

λx (car x) '(a b c)

λxyz (* x (+ y z)) 9 8 7 

(define (f x) (* x 2))

(define f (λ(x) (* x 2)))

(define f λx (* x 2))

λ関数の括弧がかなり省略できるのがわかるでしょうか。

■ 1 特徴と制限

ここで新たに作成したLispの方言は、以下のような特徴や制限を持ちます。

1. 1行ずつプログラムを読み込む。(継続行の入力はできない)
2. リストのドット対は、"."ではなく、":"を使う。
3. 使える組み込み関数は、car, cdr, cons, equal, atom, cond, λ, 
  print, define, 整数演算子、比較演算子
4. ローカル変数は設定と参照はできるが変更はできない。
   (副作用がなく参照透明性を持つ。)
5. defineで設定される変数と関数は同じグローバル名空間に設定される。
6. lamda関数を、"λ"と多バイト文字で表現する。
7. λ関数で、括弧を減らす糖衣構文(シンタックスシュガー)を導入する。
8. λ関数の中で実行する関数は一つしか書けない。
   λx (関数1)としか書けず、λx (関数1)(関数2)とは書けない。
   普通のlispと異なり、(λ (x) (関数1)(関数2))とは書けない。

できるだけシンプルになるようにデザインしました。

■ 2. 文字コードの注意点

λのような多バイト文字を使っているため、システムの文字コードと デカルト言語の文字コードと、lispプログラムの文字コードの3者を 一致させる必要があることに注意してください。

-uオプションとlisp-utf8、あるいは-sオプションとlisp-sjisのいずれか の組み合わせで正しく動作するはずです。

descartes -u lisp-utf8
または
descartes -s lisp-sjis

起動した後に以下のようにλが表示されなければなりません。

Descartes Lisp/λ (c) 2010 H.Niwa
Ready

λが表示されていなければ文字コードの設定に誤りがあります。

Descartes Lisp/■ (c) 2010 H.Niwa
Ready

■ 3. 実行例

このDescartes Lisp/λでは以下のようなプログラムを実行できます。


(car '(a b c))
(define f 1)
(define f (λ(x) (* x 2)))
(define (f x) (* x 2))
((λ(x y) (* x (+ y 3))) 2 3)
λxyz (* x (+ y z)) 9 8 7 
λx λy λz (+ x (* y z))  7 40 3
(define f λx (* x 2))
(f 3)

実行結果を以下に示します。


$ descartes -u lisp-utf8
Descartes Lisp/λ (c) 2010 H.Niwa
Ready
(car '(a b c))
a
Ready
(define f 1)
1
Ready
(define f (λ(x) (* x 2)))
(λ (x) (* x 2))
Ready
(define (f x) (* x 2))
(λ (x) (* x 2))
Ready
((λ(x y) (* x (+ y 3))) 2 3)
12
Ready
λxyz (* x (+ y z)) 9 8 7
135
Ready
λx λy λz (+ x (* y z))  7 40 3
283
Ready
(define f λx (* x 2))
(λ (x) (* x 2))
Ready
(f 3)
6
Ready

■4. ラムダ関数

デカルトLisp/λのラムダ関数は、他のlisp言語の"lambda"を"λ"に置き換えた ものです。

他のlisp言語で"(lambda (x) (+ x 1))"と書くものは、デカルトLisp/λでは "(λ(x) (+ x 1))"と書きます。

それだけでは、あまり面白くもありませんので、さらに、以下の条件の場合には、 1番外側と2番目の括弧と引数の括弧を書く必要がないようにしました。

λ計算理論で使われるλ式にかなり近い形になります。

- λ関数の引数パラメタが 1 から 3 個である。かつ。
- λ関数の引数パラメタの変数名が 英字1文字 である。かつ、
- λ関数の引数パラメタが括弧でくくられていない場合。

たとえば、以下は同じものです。

((λ(x)(+ x 1)) 1)
λx (+ x 1) 1

λとxはくっついていても大丈夫です。

実行してみましょう。


((λ(x)(+ x 1)) 1)
2
Ready
λx (+ x 1) 1
2
Ready

defineによる関数定義も同様です。


(define f (λ(x)(+ x 1)))

(define f λx (+ x 1))

ラムダ関数を入れ子にすることもできます。

λx λy (/ x y) 3 6
2

これは、以下と同じです。

((λ(x) ((λ(y) (/ x y)) 3)) 6)
2

引数パラメタ変数のxが6, yが 3にバインドされることに注意してください。 λ関数を入れ子にした場合には、与える引数が定義とは逆順にパラメタの引数に バインドされます。

複数のパラメタが一つのラムダに定義されている場合には、順にバインドされます。

λxy (/ x y) 6 3
2

((λ(x y) (/ x y)) 6 3)
2