scheme との違いは、syntax が少し異なる事と、 Scheme の static scoping に対して、 Common Lisp の scope が dynamic であること等が あげられます。また、より大きな違いとして、 Common Lisp 上の programming style では代入を頻繁に用いる事が多いです。
Common Lisp の拡張として、オブジェクト指向のCLOS (Common Lisp Object System) なども存在します。
一度は、 ~/.emacs という file をみたことがあると思いますが、これは
Emacs Lisp で記述されています。
Emacs Lisp は Emacs 上で簡単に使うことができます。
例えば、
言語の特徴は、Common Lisp に似ています。
詳しくは、elisp 用の info file を
また、mule がどこの directory にあるか見て、
その lisp program がどの様になっているか見てみるのもよいかもしれません。
つまり、 * を式の構成要素としてだけではなくて、
値そのものとして使うつもりだということです。
このように値として扱えるものを first class value といい、scheme では、
function は first class value として扱われます。
その意味では、式とは変数と定数と関数とを関数によって組み合わせたもの
というのがより正しいのかもしれません。
これに対し、引数部の評価を後まわしにして、先に関数を展開してしまうことも出来ます。
名前呼出し (call by name) などと呼ばれます。
評価順序によっては、評価に必要な step 数が変化することもあり、
問題によっては評価順序によってプログラムが無限ループに陥ってしまうことも
あります。
例えば、 loop(x) = loop(x+1), foo(x, y) = x である場合に
foo(3, loop(3)) を評価する場合を考えてみましょう。
引数、つまり、 3, loop(3) をまず評価した場合、loop(3) の評価で
無限 loop に陥りますが、 foo の評価をした場合、
foo(3, loop(3)) => 3 と正常に終了します。
より厳密には以下のように表現できます。
普通に計算が終わる場合、その式の値とは、式の正規形の事です。
これは、
C などで値を取っておくためだけの変数への代入は状態ととらえる必要が無いからです。
Scheme などでは、 let/let* を用いることで
解決しており、代入と言う形を取りません。
今回、関数的に書く技術を覚えておくと、
C でプログラミングする際もきれいなコードが書けるようになるかも知れません。
とすると、式の値が print されます。
これで、電卓 program なんぞとはおさらばです。
/usr2/home/BB/info/elisp-jp
としておいておきますので興味があれば見てみましょう。
The Revised^4 Report on the Algorithmic Language Scheme
The Revised^5 Report on the Algorithmic Language Scheme
の略です。
> (* 3)
3
> (*)
1
(case 式
((値の並び) 式が複数)
.....
((値の並び) 式が複数))
まず、式を評価し、その値が「値の並び」のなかに含まれていないか順々に評価していき、
見つかった節に連なっている式を順々に実行して行きます。節のなかに式が複数
並んでいる場合は最後の式の値を返し、 case 式の値とします。
cond と同様、最後の節については"(値の並び)"の代りに else
と書くことが出来ます。
(define (foo3 x)
(case (remainder x 8) ; remainder は余りを求める演算
((0) 0) ; 余りが 0 だと 0を返し
((1 3 5 7) 1) ; 1,3,5,7 のどれかだと 1を返し、
(else 2))) ; さもなくば 2を返す
> (foo3 14)
2
(define (関数名 引数) 複数の式)
という形を取ることができます。これは、
(define (関数名 引数) (begin 複数の式))
と同値ですので、詳しくは
begin を見て下さい。
(defun 関数名 (引数) 複数の式)
と表記されます。
> (define (loop x) (loop x)) ; loop する関数を定義
> (or #t (loop 0)) ; or の評価の際は
#t ; 真の値が出た時点で終了
> (and #t (loop 0)) ; and の評価の際は
返って来ない ; (loop) の評価をしようとして無限loop
> (define (user-or x y) (or x y)) ; user-or は二引数で or をするだけ
> (user-or #t (loop)) ; でも、一般関数の場合引数を全て評価しようとするので、
返って来ない ; 無限loop に入る
(define (mul x y) (* x y))
(define a 4)
(mul a (mul 2 a))
新たな window がでてきますので、next ボタンを押して行くと計算の進行状況が見えます。
色がついているところが、これからどこが評価され、
どうなるのかを示しています。
int counter = 0;
int inc_counter() { counter++; return counter; }
int foo(int x, int y) {
if (y == 1) {
return x;
} else {
return - x;
}
}
int main() { return foo(inc_counter(), inc_counter()); }
99.10.6/ Tomio KAMADA: kamada@cs.kobe-u.ac.jp