Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
929 lines (853 sloc) 51.7 KB
;;;;;;;;;;
;;;注意
;;; 補足説明、用語集にはgosubで飛んでくる
;;;;;;;;;;
;;;;;補足説明;;;;;
;;;各補足にgotoで飛ぶ(選択肢なのでやむなし)
;;;各補足から*condicil_loopにgotoで飛ぶ
;;;クリア状態における判定は*condicil_loopで行う
;;;;;
*condicil
speak_mode
textclear
csp SP_R : csp SP_L
r_load ari_n
bg "img/blackboard.bmp", E_FAST
*condicil_loop
if %adv_clear == 0 goto *condicil_00
if %adv_clear == 1 goto *condicil_01
if %adv_clear == 2 goto *condicil_02
if %adv_clear == 3 goto *condicil_03
if %adv_clear == 4 goto *condicil_04
if %adv_clear == 5 goto *condicil_05
if %adv_clear == 6 goto *condicil_06
if %adv_clear == 7 goto *condicil_07
if %adv_clear == 8 goto *condicil_08
if %adv_clear == 9 goto *condicil_09
if %adv_clear == 10 goto *condicil_10
if %adv_clear == 11 goto *condicil_11
if %adv_clear == 12 goto *condicil_12
*condicil_end
textclear
csp SP_R
bg black, E_FAST
return
*condicil_00
アリサ「読みたい補足説明を選択してね」
csel "このソフトについて", *cdc_game, "戻る", *condicil_end
*condicil_01
アリサ「読みたい補足説明を選択してね」
csel "このソフトについて", *cdc_game, "戻る", *condicil_end
*condicil_02
アリサ「読みたい補足説明を選択してね」
csel "このソフトについて", *cdc_game, "シンボル・式の評価", *cdc_eval, "戻る", *condicil_end
*condicil_03
アリサ「読みたい補足説明を選択してね」
csel "このソフトについて", *cdc_game, "シンボル・式の評価", *cdc_eval, "型の調べ方", *cdc_type, "戻る", *condicil_end
*condicil_04
アリサ「読みたい補足説明を選択してね」
csel "このソフトについて", *cdc_game, "シンボル・式の評価", *cdc_eval, "型の調べ方", *cdc_type, "list", *cdc_list, "図の描き方", *cdc_chart, "行儀の悪いリスト", *cdc_improperlist, "戻る", *condicil_end
*condicil_05
アリサ「読みたい補足説明を選択してね」
csel "このソフトについて", *cdc_game, "シンボル・式の評価", *cdc_eval, "型の調べ方", *cdc_type, "list", *cdc_list, "図の描き方", *cdc_chart, "行儀の悪いリスト", *cdc_improperlist, "cxr", *cdc_cxr, "戻る", *condicil_end
*condicil_06
アリサ「読みたい補足説明を選択してね」
csel "このソフトについて", *cdc_game, "シンボル・式の評価", *cdc_eval, "型の調べ方", *cdc_type, "list", *cdc_list, "図の描き方", *cdc_chart, "行儀の悪いリスト", *cdc_improperlist, "cxr", *cdc_cxr, "condでifを作る?", *cdc_condif, "置き換えによる再帰", *cdc_recursion, "戻る", *condicil_end
*condicil_07
アリサ「読みたい補足説明を選択してね」
csel "このソフトについて", *cdc_game, "シンボル・式の評価", *cdc_eval, "型の調べ方", *cdc_type, "list", *cdc_list, "図の描き方", *cdc_chart, "行儀の悪いリスト", *cdc_improperlist, "cxr", *cdc_cxr, "condでifを作る?", *cdc_condif, "置き換えによる再帰", *cdc_recursion, "方言によるスコープの違い", *cdc_scope, "戻る", *condicil_end
*condicil_08
アリサ「読みたい補足説明を選択してね」
csel "このソフトについて", *cdc_game, "シンボル・式の評価", *cdc_eval, "型の調べ方", *cdc_type, "list", *cdc_list, "図の描き方", *cdc_chart, "行儀の悪いリスト", *cdc_improperlist, "cxr", *cdc_cxr, "condでifを作る?", *cdc_condif, "置き換えによる再帰", *cdc_recursion, "方言によるスコープの違い", *cdc_scope, "感嘆符!の付く関数", *cdc_ban, "戻る", *condicil_end
*condicil_09
アリサ「読みたい補足説明を選択してね」
csel "このソフトについて", *cdc_game, "シンボル・式の評価", *cdc_eval, "型の調べ方", *cdc_type, "list", *cdc_list, "図の描き方", *cdc_chart, "行儀の悪いリスト", *cdc_improperlist, "cxr", *cdc_cxr, "condでifを作る?", *cdc_condif, "置き換えによる再帰", *cdc_recursion, "方言によるスコープの違い", *cdc_scope, "感嘆符!の付く関数", *cdc_ban, "置き換えによる末尾再帰", *cdc_tailrecursion, "リストの共有構造", *cdc_listshare, "戻る", *condicil_end
*condicil_10
アリサ「読みたい補足説明を選択してね」
csel "このソフトについて", *cdc_game, "シンボル・式の評価", *cdc_eval, "型の調べ方", *cdc_type, "list", *cdc_list, "図の描き方", *cdc_chart, "行儀の悪いリスト", *cdc_improperlist, "cxr", *cdc_cxr, "condでifを作る?", *cdc_condif, "置き換えによる再帰", *cdc_recursion, "方言によるスコープの違い", *cdc_scope, "感嘆符!の付く関数", *cdc_ban, "置き換えによる末尾再帰", *cdc_tailrecursion, "リストの共有構造", *cdc_listshare, "eval", *cdc_eval2, "apply", *cdc_apply, "append", *cdc_append, "戻る", *condicil_end
*condicil_11
アリサ「読みたい補足説明を選択してね」
csel "このソフトについて", *cdc_game, "シンボル・式の評価", *cdc_eval, "型の調べ方", *cdc_type, "list", *cdc_list, "図の描き方", *cdc_chart, "行儀の悪いリスト", *cdc_improperlist, "cxr", *cdc_cxr, "condでifを作る?", *cdc_condif, "置き換えによる再帰", *cdc_recursion, "方言によるスコープの違い", *cdc_scope, "感嘆符!の付く関数", *cdc_ban, "置き換えによる末尾再帰", *cdc_tailrecursion, "リストの共有構造", *cdc_listshare, "eval", *cdc_eval2, "apply", *cdc_apply, "append", *cdc_append, "残余引数", *cdc_restparameter, "戻る", *condicil_end
*condicil_12
アリサ「読みたい補足説明を選択してね」
csel "このソフトについて", *cdc_game, "シンボル・式の評価", *cdc_eval, "型の調べ方", *cdc_type, "list", *cdc_list, "図の描き方", *cdc_chart, "行儀の悪いリスト", *cdc_improperlist, "cxr", *cdc_cxr, "condでifを作る?", *cdc_condif, "置き換えによる再帰", *cdc_recursion, "方言によるスコープの違い", *cdc_scope, "感嘆符!の付く関数", *cdc_ban, "置き換えによる末尾再帰", *cdc_tailrecursion, "リストの共有構造", *cdc_listshare, "eval", *cdc_eval2, "apply", *cdc_apply, "append", *cdc_append, "残余引数", *cdc_restparameter, "団子数の割り算", *cdc_div, "戻る", *condicil_end
*cdc_game
アリサ「このソフトについて簡単に説明するわね。@/
このソフトは物語を読みながら実際に触れてみて、Lispを学んだ#FFFF33気分になる#FFFFFFものよ。@/
本気でLispを学びたかったら、ちゃんとした本を買って勉強することを薦めるわ。@/
まあ、それでもこのソフトで遊んでくれた方が私は嬉しいけど……。@
ゲーム本編以外にあるのが、この#FFFF33補足説明#FFFFFFと#FFFF33用語集#FFFFFFね。@/
どちらも、本編では言い切れなかったことの説明のために書かれたもので、物語の進行と共に増えていくわ」\
アリサ「こんなもんやらなくてもLispぐらい知ってるというという人のために#FFFF33フリーモード#FFFFFFというものも用意したわ。@/
これは、NScLisperを触るためだけの機能ね。@/
ここで扱うLispは#FFFF33Scheme#FFFFFFライクなもので、組み込み関数の名前は、ほぼSchemeよ。@/
ただし、中身は……まあ、独自のLisp方言とでもいっておきましょう。@/
関数と変数のネームスペースも同一で、funcallとかは不必要になってるわ。@/
ただ、所々変なところがあって、Schemeのサブセットにはなっていないから『Schemeです』とは言い難いわね」\
goto *condicil_loop
*cdc_calc
アリサ「四則演算について簡単に復習してみましょう。@
足し算#33FF33(+ 1 1)#FFFFFF⇒#33FF332#FFFFFF@
引き算#33FF33(- 5 2)#FFFFFF⇒#33FF333#FFFFFF@
掛け算#33FF33(* 6 4)#FFFFFF⇒#33FF3324#FFFFFF@
割り算#33FF33(/ 9 3)#FFFFFF⇒#33FF333#FFFFFF@
『⇒』は『評価した結果は…』という意味で使ってるわ」\
アリサ「どれも書き方は
#33FF33(演算子 数1 数2)#FFFFFF
となっているのが特徴ね。@/
括弧の中で#FFFF33演算子、被演算子#FFFFFFという順番で現れているでしょ。@/
Lispでは四則演算に限らず、この順番はすべて共通で、
#33FF33(演算子 被演算子1 被演算子2…被演算子n)#FFFFFF
という風に式を書くのよ」\
goto *condicil_loop
*cdc_eval
アリサ「シンボルと式の評価について簡単に復習してみましょう。@
まず、式の評価というのは評価の対象となる#FFFF33式#FFFFFFと、#FFFF33環境#FFFFFFの二つを使って行われるの。@/
環境は、変数の束縛の情報が入っているの。@/
シンボルを評価すると、この環境から変数の値が探されて、それが結果となるわ。@/
一度#33FF33(define x 2)#FFFFFFを評価すると、環境に『xは2に束縛された』と記憶されるわ。@/
この後の評価においても同じ環境が使われるから、/
#33FF33x#FFFFFFを評価すると2という結果になるわ。@
一方、数を評価すると、結果は評価する前と同じ数になるの。@/
#33FF33(+ 6 7)#FFFFFFみたいな式を評価するときにも、6が評価されて6になって、
7が評価されて7になってから+による足し算が行われて13という結果になるのよ」\
goto *condicil_loop
*cdc_type
アリサ「#FFFF33型#FFFFFFとは、値の種類のことよ。@/
例えば、#33FF3357#FFFFFFという値の型は『数』、@/
#33FF33shamal#FFFFFFという値の型は『シンボル』よ。@/
プログラミング言語によっては変数と型が結びついているものもあるけど、/
Lispは値と型が結びついていているの。@/
だから、どんな変数も好きな型の値で束縛できるのよ」\
アリサ「それから、値の型を調べる関数というものも用意されていて、
#33FF33/
(number? 19)⇒#t
(symbol? 19)⇒#f
(number? ’a)⇒#f
(symbol? ’a)⇒#t#FFFFFF
関数#33FF33number?#FFFFFFは、引数の型が数なら#33FF33#t#FFFFFF、それ以外なら#33FF33#f#FFFFFFという値を返すわ。@/
関数#33FF33symbol?#FFFFFFは、引数の型がシンボルなら#33FF33#t#FFFFFF、それ以外なら#33FF33#f#FFFFFFという値を返すわ。@/
この二つの値の意味や使い方は6話でやるわね。@/
今は#FFFF33値の型を調べる関数がある#FFFFFFということを覚えておくといいわ」\
goto *condicil_loop
*cdc_list
アリサ「リストを作るうえで#33FF33list#FFFFFFという便利な関数があるの。@
この関数は、任意個の引数を取る関数で、次のように使うわ。@
#33FF33/
(list 1 2 3)⇒(1 2 3)#FFFFFF
これだけだと、#33FF33’(1 2 3)#FFFFFFと書くのと同じように思えるかもしれないけど、@
#33FF33/
(define x 2)⇒x
(list 1 x 3)⇒(1 2 3)#FFFFFF
この例を見れば分かるとおり、listは引数を評価してるの。@/
単にリストをquoteした、#33FF33’(1 x 3)#FFFFFFを評価しても、/
式の値は#33FF33(1 x 3)#FFFFFFとしかならないの。@/
この違いをちゃんと考えてquoteとlistを使い分けてね」\
goto *condicil_loop
*cdc_chart
アリサ「リストの構造を考えるときは図を描くのが有効なの。@/
図は案外単純な規則で描く事ができるのよ」\
アリサ「#33FF33(A X Y B)#FFFFFFのようなリストを考えてみましょう。@/
まず、リストを見たら、箱を二つ書いて、一つ目の箱から矢印を下に出して、そこに一つ目の要素を描くの。この場合#33FF33A#FFFFFFね。@/
そして、二つ目の箱から矢印を右に出して、その先にリストの残りの部分の図を描くわ。@/
show_dgm ":l;img/dgm_cdc_chart01a.bmp"
残りの部分というと、この場合は#33FF33(X Y B)#FFFFFFのことで、今度はAの代わりにXを取り出して同じことをするわ。@/
リストの最後の要素にたどり着いたら、一つ目の箱からは下に矢印を出して、そこに最後の要素を書いて、二つ目の箱には斜線を引くの。@/
show_dgm ":l;img/dgm_cdc_chart01b.bmp"
この斜線は『空リストが入っています』という意味なのよ。これで、簡単なリストの図はもう描けるわね」\
csp SP_DGM0 : print E_FAST
アリサ「次に、#33FF33(A . B)#FFFFFFのようなコンスを考えてみましょう。@/
これは箱を二つ書いて、一つ目からはCARの要素へ矢印を書き、二つ目からはCDRの要素への矢印を描くだけよ。@/
show_dgm ":l;img/dgm_cdc_chart02a.bmp"
最後に、#33FF33(X A . B)#FFFFFFという行儀の悪いリストも考えてみましょう。@/
これは、最初は普通のリストと同じ書き方をしていくと、最後に#33FF33(A . B)#FFFFFFというコンスが残るので、/
あとは同じ書き方をするだけよ@/
show_dgm ":l;img/dgm_cdc_chart02b.bmp"
普通のリストの図がかければこっちも書けるはずよ」\
csp SP_DGM0 : print E_FAST
アリサ「それでは、実際にちょっと複雑な例を見てみましょう。@/
いままで#33FF33A#FFFFFF等と大文字で表してきた箇所はリストでもかまわないの。@
#33FF33((a . b)c(d))#FFFFFF
このリストを描くことを考えてみるわね。@/
最初は例にならって、箱を二つ書いて、一つ目の箱から下に矢印を出すの。@/
そして、最初の要素である#33FF33(a . b)#FFFFFFを描くんだけど、これもコンスなので、/
再び箱を書いてからaとbへの矢印を描くわ。@/
show_dgm ":l;img/dgm_cdc_chart03a.bmp"
あとは、これまでに言った規則を当てはめていくだけで自然に図が描けるはずよ。@/
show_dgm ":l;img/dgm_cdc_chart03b.bmp"
スラスラと図が描けるようになるまで、適当なリストを見るたびに図を描いてみることをお勧めするわ」\
csp SP_DGM0 : print E_FAST
goto *condicil_loop
*cdc_improperlist
アリサ「リストとは@
1.空リスト
2.CDRにリストを持つコンス
のことなの。@/
リストの説明をしているのに、『2』の方でリストという言葉を使っているのが違和感を感じるかもしれないわね。@/
まず、『1』より、空リストはリストね。@/
それから、『2』より、CDRに空リストを持つコンスもリストね。@/
そして、そのコンスをCDRにもつコンスもリストと言えるわけ。@/
とにかく、リストとは、#FFFF33最後のコンスのCDRが必ず空リスト#FFFFFFなの。@/
それじゃあ、#33FF33(a b . c)#FFFFFFみたいに、最後のコンスのCDRが空リスト以外のものは何かというと、@/
これは#FFFF33行儀の悪いリスト#FFFFFFなどと呼ぶわ。@/
普通、『リストに対して○○をする関数』に対して行儀の悪いリストを送ると正しくない結果が返るわ。@/
リストがある程度分かるまでは行儀の悪いリストはあまり使わない方がいいと思うわ」\
goto *condicil_loop
*cdc_cxr
アリサ「Lispではcarやcdrを重ねて使いたいときが多いの。@/
例えば、#33FF33(car (car x))#FFFFFFとか、#33FF33(car (cdr x))#FFFFFFといった感じにね。@/
これらはよく使うから、簡単に書くための関数が用意されていて、それぞれは、#33FF33(caar x)#FFFFFF、#33FF33(cadr x)#FFFFFFという風に書けるの。@/
#33FF33caar#FFFFFFは、CARをとった後にCARを取る関数、/
#33FF33cadr#FFFFFFは、CDRをとった後にCARを取る関数よ。@/
他にも#33FF33cdar#FFFFFFみたいに、aとdを入れ替えた似たような関数がたくさんあるの。@/
これらの関数の名前は、最初はc、最後はrと決まっているわ。@/
処理系によっては#33FF33cadaddadr#FFFFFFみたいな長いものも用意されているけど、/
NScLisperでは#33FF33cxxr#FFFFFFみたいに二つ続けたものしか用意されてないわ。注意してね」\
goto *condicil_loop
*cdc_condif
アリサ「condを使ってifを作ってみましょう。
#33FF33/
(define my-if
 (lambda (c x y)
  (cond
   (c x)
   (else y))))#FFFFFF
こうやって作った関数#33FF33my-if#FFFFFF。@
#33FF33/
(my-if (= 0 0)
       1
       2)⇒1#FFFFFF
使ってみたらこんな結果になるし、一見上手くいきそうなんだけど、実は問題があるの。@/
何でだと思う?」\
アリサ「問題はmy-ifが関数であるが故に、引数を評価するところにあるわ。
#33FF33
(my-if (= n 0)
       0
       (f (- n 1)))#FFFFFF
こんな式を評価しようとすると、nの値にかかわらず、関数fが呼ばれるわ。@/
つまり、my-ifを使って再帰を書こうとすると、関数が呼ばれ続け、永遠に終わらないの。@/
要するに関数である以上、condを使ってifを書いたり、その逆もできないって言うこと。@/
そういったことをやりたい場合は#FFFF33マクロ#FFFFFFと呼ばれるものを使うんだけど、/
NScLisperはマクロを実装してないからこの話は割愛するわね」\
goto *condicil_loop
*cdc_recursion
アリサ「関数の呼び出しを考えるとき、仮引数を実引数で置き換えると分かりやすいという話があったわよね。@/
これを、再帰を使う関数で考えてみましょう。@
#33FF33/
(define f
 (lambda (n)
  (if
   (= n 0)
   1
   (* n (f (- n 1))))))#FFFFFF
関数fをこう定義した後に、#33FF33(f 2)#FFFFFFという式を評価する場合を考えるわね。@/
関数の中に出てくる仮引数nを実引数2で置き換えると次のようになるわ。@
#33FF33/
(if
 (= 2 0)
 1
 (* 2 (f (- 2 1))))))#FFFFFF
@ifによって、第3引数が評価されるので、評価されるのは結局、
#33FF33/
(* 2 (f (- 2 1)))#FFFFFF
という式ね。@/
この中に#33FF33(f (- 2 1))#FFFFFFという関数呼び出しがまた含まれているわね」\
アリサ「ここで、
#33FF33(* 2 (f (- 2 1)))#FFFFFF
のfの呼び出しの部分も仮引数nを実引数1で置き換えることを考えましょう。@/
ただし、ifの部分は評価される式だけを取り出すわね。そうすると、@
#33FF33/
(* 2 (* 1 (f (- 1 1))))#FFFFFF
さらに、仮引数nを実引数0で置き換えると、@
#33FF33/
(* 2 (* 1 1))#FFFFFF
これでようやく関数呼び出しが終わって、式の値が求まるわね」\
アリサ「ここで重要なのが、このような関数では、再帰が終わるまで、/
実際の計算(この場合掛け算)が待たされるということ。@/
部分式を評価したもので置き換えていくと、式がどんどん長くなっていくのが特徴ね」\
goto *condicil_loop
*cdc_scope
アリサ「次のような3つの式を考えてみましょう。
#33FF33
(define y 1)
(define f
 (lambda (x)
  (+ x y)))
(define g
 (lambda (y)
  (f 2)))#FFFFFF
ここで、#33FF33(g 10)#FFFFFFという式の値はどうなると思う?@/
 レキシカルスコープであるSchemeでは、関数fからは、関数gの内側にあるyは見えないの。@/
だから、大域変数のyの値が使われて、#33FF333#FFFFFFとなるわ。@/
ただし、Lisp方言の一つであるelispでは、fからgのyが見えて、式の値は#33FF3312#FFFFFFとなるの。@/
これは、elispが#FFFF33ダイナミックスコープ#FFFFFFという規則を採用しているからよ。@/
実はCommonLispも部分的にダイナミックスコープが使えて、elispと同じようなことができるの。@/
ダイナミックスコープについてはここでは触れないから、興味があったら自分で調べてね」\
goto *condicil_loop
*cdc_ban
アリサ「#33FF33set!#FFFFFFを始め、Schemeには名前の最後に『!』をつけた関数がいくつかあるの。@/
これは何かを破壊的に書き換える関数という意味なの。@/
だから、内部でset!を呼び出す関数も名前の最後に『!』をつけたりもするわ。@/
ちなみに、発音するときはこの『!』は『バン』と発音するのよ。@/
set!は『セットバン』という感じにね」\
goto *condicil_loop
*cdc_tailrecursion
アリサ「末尾再帰を使った関数に対して、仮引数を実引数で置き換えるという考え方を使ってみましょう。@/
#33FF33/
(define (f n x)
 (if
  (= n 0)
  x
  (f (- n 1)
     (* n x))))#FFFFFF
ここで、#33FF33(f 2 1)#FFFFFFを評価する場合を考えるわね。@/
ifの部分は評価される式だけ取り出すとすると、まずは、@
#33FF33(f (- 2 1) (* 2 1))#FFFFFF
という式に変わるわね。これもまた関数呼び出しだから、仮引数n、xを実引数1、2で置き換えると、@
#33FF33(f (- 1 1) (* 1 2))#FFFFFF
同様に仮引数n、xを実引数0、2で置き換えると#33FF332#FFFFFFになるわ。@/
普通の再帰の場合と違って、部分式を評価したもので置き換えても式は長くならないの。
だから、単純な繰り返しの形に自動的に変わるのよ」\
goto *condicil_loop
*cdc_listshare
アリサ「リストの破壊的操作をする場合、コンスが共有されているかどうかを気にする必要があるわ。@/
その際、最低限覚えておくことは、carやcdrを使うと、それが共有されること。@/
show_dgm ":l;img/dgm_cdc_listshare01.bmp"
csp SP_DGM0 : print E_FAST
それと、consを使うと必ず新しいコンスが作られるから共有されないということ。@/
だから、新しいリストを作るときはconsを何度も呼ぶことになるわ。@/
例えば、リストをコピーする関数を考えてみましょう。
#33FF33/
(define (cp l)
 (if
  (null? l)
  ’()
  (cons
   (car l)
   (cp (cdr l)))))#FFFFFF
これで、コンスを共有せずにコピーできるように見えるけど、実は問題があるの」\
アリサ「この定義だと、#33FF33((a)b)#FFFFFFのようにコンスのCARにコンスがある場合、そのコンスが共有されてしまうわ。@/
show_dgm ":l;img/dgm_cdc_listshare02.bmp"
csp SP_DGM0 : print E_FAST
そこで、型がコンスか確かめる述語#33FF33pair?#FFFFFFを使って、次のように書き直せるの。@
#33FF33
(define (cp l)
 (if
  (pair? l)
  (cons(cp (car l))
       (cp (cdr l)))
  l))#FFFFFF
もちろん、pair?は、引数の型がコンスなら#t、そうでなければ#fを返す関数よ。
このように、再帰的にcpを呼び出すことによって、コンスを共有することなくリストをコピーできるわ。@/
少々ややこしいかもしれないけど、しっかりと考えたら仕組みは自然と分かるはずよ」\
goto *condicil_loop
*cdc_eval2
アリサ「関数#33FF33eval#FFFFFFの引数として、quoteした式を与えると、その式を評価してくれるわね。@/
けど、式を評価するには何かが足りてないと思わない?@/
 そう。式を評価するには『環境』が必ずいるでしょ。@/
NScLisperでは、evalは式を評価する環境として、大域環境を使うようになってるけど、/
処理系によってはevalの第2引数として環境を指定するものもあるわ。@/
環境の取得の方法とかいった詳細は自分で調べてね」\
goto *condicil_loop
*cdc_apply
アリサ「Lispの便利な関数の一つとして、#33FF33apply#FFFFFFというものがあるの。@/
これは、関数と#FFFF33引数のリスト#FFFFFFを受け取って、関数呼び出しを行うものよ。@/
とりあえず、実際に使ってみましょう。@
#33FF33
(apply + ’(1 2))⇒3
(apply cons
       ’(a b))⇒(a . b)#FFFFFF
関数に送る引数をリストの形で渡せるというのがこの関数の便利なところなの。@/
どう便利かというと……@/
使いたくなったときにきっと便利と気付くはずよ」\
goto *condicil_loop
*cdc_append
アリサ「10話の最後にいった/
『#33FF33(a b)#FFFFFFと#33FF33(c d)#FFFFFFを受け取って、#33FF33(a b c d)#FFFFFFを返す関数』/
というものを作ってみましょう。@/
;図が欲しい
第1引数の最後に入っている空リストを第2引数と置き換えたらいいんだから、リストをコピーする関数をすこし書き換えれば上手くいくわ。@
#33FF33
(define (f x y)
 (if
  (null? x)
  y
  (cons
   (car x)
   (f (cdr x) y))))#FFFFFF
ちなみに普通、Lispにはこれと同じ動作をする#33FF33append#FFFFFFという関数が最初から用意されているわ」\
goto *condicil_loop
*cdc_restparameter
アリサ「これまで作ってきた関数は取れる引数の数が決まっていたわよね。@/
ここでは任意個の引数を取ることのできる関数を作ってみましょう。@
#33FF33/
(define f
 (lambda x
  x))     ⇒f
(f 1 2 3) ⇒(1 2 3)#FFFFFF
このように、#33FF33(lambda 変数 式)#FFFFFFと書くと、/
変数は#FFFF33実引数のリスト#FFFFFFで束縛されるの。@/
変数のリストとは#33FF33(f 1 2 3)#FFFFFFという関数呼び出しの場合、#33FF33(1 2 3)#FFFFFFのことよ」\
アリサ「また、一つ以上の任意個の引数をとる場合は、
#33FF33(lambda (x . rest) 式)#FFFFFF
のように書くといいわ。こうすると、xは一つ目の実引数に束縛されて、restが二つ目以降の引数のリストで束縛されるわ。@/
二つ目以降の引数のリストとは、#33FF33(f 1 2 3)#FFFFFFという関数呼び出しの場合、#33FF33(2 3)#FFFFFFのことよ。@/
同様に、二つ以上の任意個の引数をとる場合は、
#33FF33(lambda (x y . rest) 式)#FFFFFF
三つ以上の場合もやり方は同じよ」\
goto *condicil_loop
*cdc_div
アリサ「団子数の割り算を考えてみましょう。@/
『x割るy』は、xからyを何回引けばyがxより大きくなるか、その回数を求めるものと考えられるわね。@/
ただしこれをやるには、xとyのどちらが大きいかを比較する関数を先に作る必要があるわね。@
#33FF33/
(define (ge? x y)
 (if
  (null? (sub y x))
  #t
  #f))#FFFFFF
この関数は第1引数が第2引数以上ならば#t、そうでなければ#fを返すわ。@/
subは引く数の方が引かれる数以上なら団子数0を返すように作ってるからこう書けるのよ」\
アリサ「じゃあ、この関数を使って割り算を作ってみましょう。
#33FF33/
(define (div x y)
 (divi x y (zero))
(define (divi x y n)
 (if
  (ge? x y)
  (divi
   (sub x y)
   y
   (inc n))
  n))#FFFFFF
yがxよりも大きければnを返す。@/
そうでなければxをy引いて、nを1加えて計算を繰り返す。@/
こうやって割り算を定義できるわ。@/
ただし、yが団子数0の場合、永遠に計算が終わらないから、/
yが0かどうかdivで確かめた方がいいかもしれないわね」\
goto *condicil_loop
;;;;;用語集;;;;;
;;;各用語にgotoで飛ぶ(選択肢なのでやむなし)
;;;各用語から*glossary_loopにgotoで飛ぶ
;;;クリア状態における判定は*glossary_loopで行う
;;;;;
*glossary
speak_mode
textclear
csp SP_R : csp SP_L
r_load ari_n
bg "img/blackboard.bmp", E_FAST
mov %adv_tmp, 0
*glossary_loop
if %adv_clear == 0 goto *glossary_00
if %adv_clear == 1 goto *glossary_01
if %adv_clear == 2 goto *glossary_02
if %adv_clear == 3 goto *glossary_03
if %adv_clear == 4 goto *glossary_04
if %adv_clear == 5 && %adv_tmp == 0 goto *glossary_05
if %adv_clear == 5 && %adv_tmp == 1 goto *glossary_05_2
if %adv_clear == 6 && %adv_tmp == 0 goto *glossary_06
if %adv_clear == 6 && %adv_tmp == 1 goto *glossary_06_2
if %adv_clear == 7 && %adv_tmp == 0 goto *glossary_07
if %adv_clear == 7 && %adv_tmp == 1 goto *glossary_07_2
if %adv_clear == 8 && %adv_tmp == 0 goto *glossary_08
if %adv_clear == 8 && %adv_tmp == 1 goto *glossary_08_2
if %adv_clear == 9 && %adv_tmp == 0 goto *glossary_09
if %adv_clear == 9 && %adv_tmp == 1 goto *glossary_09_2
if %adv_clear == 10 && %adv_tmp == 0 goto *glossary_10
if %adv_clear == 10 && %adv_tmp == 1 goto *glossary_10_2
if %adv_clear == 11 && %adv_tmp == 0 goto *glossary_11
if %adv_clear == 11 && %adv_tmp == 1 goto *glossary_11_2
if %adv_clear == 12 && %adv_tmp == 0 goto *glossary_12
if %adv_clear == 12 && %adv_tmp == 1 goto *glossary_12_2
*glossary_end
textclear
csp SP_R
bg black, E_FAST
return
*glossary_00
アリサ「読みたい単語を選択してね」
csel "NScLisper", *gls_nsclisper, "戻る", *glossary_end
*glossary_01
アリサ「読みたい単語を選択してね」
csel "NScLisper", *gls_nsclisper, "Lisp", *gls_lisp, "NScripter", *gls_nscripter, "式", *gls_expr, "評価", *gls_eval, "REPL", *gls_repl, "演算子・被演算子", *gls_operator, "戻る", *glossary_end
*glossary_02
アリサ「読みたい単語を選択してね」
csel "NScLisper", *gls_nsclisper, "Lisp", *gls_lisp, "NScripter", *gls_nscripter, "式", *gls_expr, "評価", *gls_eval, "REPL", *gls_repl, "演算子・被演算子", *gls_operator, "方言", *gls_hogen, "Scheme", *gls_scheme, "シンボル", *gls_symbol, "数", *gls_num, "束縛", *gls_bind, "変数", *gls_variable, "環境", *gls_env, "戻る", *glossary_end
*glossary_03
アリサ「読みたい単語を選択してね」
csel "NScLisper", *gls_nsclisper, "Lisp", *gls_lisp, "NScripter", *gls_nscripter, "式", *gls_expr, "評価", *gls_eval, "REPL", *gls_repl, "演算子・被演算子", *gls_operator, "方言", *gls_hogen, "Scheme", *gls_scheme, "シンボル", *gls_symbol, "数", *gls_num, "束縛", *gls_bind, "変数", *gls_variable, "環境", *gls_env, "アトム", *gls_atom, "quote", *gls_quote, "値", *gls_value, "関数", *gls_function, "スペシャルフォーム", *gls_special, "戻る", *glossary_end
*glossary_04
アリサ「読みたい単語を選択してね」
csel "NScLisper", *gls_nsclisper, "Lisp", *gls_lisp, "NScripter", *gls_nscripter, "式", *gls_expr, "評価", *gls_eval, "REPL", *gls_repl, "演算子・被演算子", *gls_operator, "方言", *gls_hogen, "Scheme", *gls_scheme, "シンボル", *gls_symbol, "数", *gls_num, "束縛", *gls_bind, "変数", *gls_variable, "環境", *gls_env, "アトム", *gls_atom, "quote", *gls_quote, "値", *gls_value, "関数", *gls_function, "スペシャルフォーム", *gls_special, "コンス", *gls_cons, "リスト", *gls_list, "S式", *gls_sform, "番地", *gls_address, "戻る", *glossary_end
*glossary_05
mov %adv_tmp, 0
アリサ「読みたい単語を選択してね」
csel "NScLisper", *gls_nsclisper, "Lisp", *gls_lisp, "NScripter", *gls_nscripter, "式", *gls_expr, "評価", *gls_eval, "REPL", *gls_repl, "演算子・被演算子", *gls_operator, "方言", *gls_hogen, "Scheme", *gls_scheme, "シンボル", *gls_symbol, "数", *gls_num, "束縛", *gls_bind, "変数", *gls_variable, "環境", *gls_env, "アトム", *gls_atom, "quote", *gls_quote, "値", *gls_value, "関数", *gls_function, "スペシャルフォーム", *gls_special, "コンス", *gls_cons, "リスト", *gls_list, "S式", *gls_sform, "番地", *gls_address, "λ山", *gls_mtlambda, "lambda", *gls_lambda, "束縛変数", *gls_bound, "次へ", *glossary_05_2, "戻る", *glossary_end
*glossary_05_2
mov %adv_tmp, 1
csel "自由変数", *gls_free, "前へ", *glossary_05, "戻る", *glossary_end
*glossary_06
mov %adv_tmp, 0
アリサ「読みたい単語を選択してね」
csel "NScLisper", *gls_nsclisper, "Lisp", *gls_lisp, "NScripter", *gls_nscripter, "式", *gls_expr, "評価", *gls_eval, "REPL", *gls_repl, "演算子・被演算子", *gls_operator, "方言", *gls_hogen, "Scheme", *gls_scheme, "シンボル", *gls_symbol, "数", *gls_num, "束縛", *gls_bind, "変数", *gls_variable, "環境", *gls_env, "アトム", *gls_atom, "quote", *gls_quote, "値", *gls_value, "関数", *gls_function, "スペシャルフォーム", *gls_special, "コンス", *gls_cons, "リスト", *gls_list, "S式", *gls_sform, "番地", *gls_address, "λ山", *gls_mtlambda, "lambda", *gls_lambda, "束縛変数", *gls_bound, "次へ", *glossary_06_2, "戻る", *glossary_end
*glossary_06_2
mov %adv_tmp, 1
csel "自由変数", *gls_free, "再帰", *gls_recursion, "糖衣構文", *gls_syntaxsugar, "前へ", *glossary_06, "戻る", *glossary_end
*glossary_07
mov %adv_tmp, 0
アリサ「読みたい単語を選択してね」
csel "NScLisper", *gls_nsclisper, "Lisp", *gls_lisp, "NScripter", *gls_nscripter, "式", *gls_expr, "評価", *gls_eval, "REPL", *gls_repl, "演算子・被演算子", *gls_operator, "方言", *gls_hogen, "Scheme", *gls_scheme, "シンボル", *gls_symbol, "数", *gls_num, "束縛", *gls_bind, "変数", *gls_variable, "環境", *gls_env, "アトム", *gls_atom, "quote", *gls_quote, "値", *gls_value, "関数", *gls_function, "スペシャルフォーム", *gls_special, "コンス", *gls_cons, "リスト", *gls_list, "S式", *gls_sform, "番地", *gls_address, "λ山", *gls_mtlambda, "lambda", *gls_lambda, "束縛変数", *gls_bound, "次へ", *glossary_07_2, "戻る", *glossary_end
*glossary_07_2
mov %adv_tmp, 1
csel "自由変数", *gls_free, "再帰", *gls_recursion, "糖衣構文", *gls_syntaxsugar, "大域環境", *gls_globalenv, "スコープ", *gls_scope, "局所変数", *gls_localvar, "述語", *gls_predicate, "火星λ", *gls_mars, "前へ", *glossary_07, "戻る", *glossary_end
*glossary_08
mov %adv_tmp, 0
アリサ「読みたい単語を選択してね」
csel "NScLisper", *gls_nsclisper, "Lisp", *gls_lisp, "NScripter", *gls_nscripter, "式", *gls_expr, "評価", *gls_eval, "REPL", *gls_repl, "演算子・被演算子", *gls_operator, "方言", *gls_hogen, "Scheme", *gls_scheme, "シンボル", *gls_symbol, "数", *gls_num, "束縛", *gls_bind, "変数", *gls_variable, "環境", *gls_env, "アトム", *gls_atom, "quote", *gls_quote, "値", *gls_value, "関数", *gls_function, "スペシャルフォーム", *gls_special, "コンス", *gls_cons, "リスト", *gls_list, "S式", *gls_sform, "番地", *gls_address, "λ山", *gls_mtlambda, "lambda", *gls_lambd, "束縛変数", *gls_bound, "次へ", *glossary_08_2, "戻る", *glossary_end
*glossary_08_2
mov %adv_tmp, 1
csel "自由変数", *gls_free, "再帰", *gls_recursion, "糖衣構文", *gls_syntaxsugar, "大域環境", *gls_globalenv, "スコープ", *gls_scope, "局所変数", *gls_localvar, "述語", *gls_predicate, "火星λ", *gls_mars, "副作用", *gls_sideeffect, "クロージャ", *gls_closure, "GC", *gls_gc, "前へ", *glossary_08, "戻る", *glossary_end
*glossary_09
mov %adv_tmp, 0
アリサ「読みたい単語を選択してね」
csel "NScLisper", *gls_nsclisper, "Lisp", *gls_lisp, "NScripter", *gls_nscripter, "式", *gls_expr, "評価", *gls_eval, "REPL", *gls_repl, "演算子・被演算子", *gls_operator, "方言", *gls_hogen, "Scheme", *gls_scheme, "シンボル", *gls_symbol, "数", *gls_num, "束縛", *gls_bind, "変数", *gls_variable, "環境", *gls_env, "アトム", *gls_atom, "quote", *gls_quote, "値", *gls_value, "関数", *gls_function, "スペシャルフォーム", *gls_special, "コンス", *gls_cons, "リスト", *gls_list, "S式", *gls_sform, "番地", *gls_address, "λ山", *gls_mtlambda, "lambda", *gls_lambda, "束縛変数", *gls_bound, "次へ", *glossary_09_2, "戻る", *glossary_end
*glossary_09_2
mov %adv_tmp, 1
csel "自由変数", *gls_free, "再帰", *gls_recursion, "糖衣構文", *gls_syntaxsugar, "大域環境", *gls_globalenv, "スコープ", *gls_scope, "局所変数", *gls_localvar, "述語", *gls_predicate, "火星λ", *gls_mars, "副作用", *gls_sideeffect, "クロージャ", *gls_closure, "GC", *gls_gc, "リストの破壊的操作", *gls_listdestructive, "末尾再帰", *gls_tailrecursion, "末尾呼出", *gls_tailcall, "前へ", *glossary_09, "戻る", *glossary_end
*glossary_10
mov %adv_tmp, 0
アリサ「読みたい単語を選択してね」
csel "NScLisper", *gls_nsclisper, "Lisp", *gls_lisp, "NScripter", *gls_nscripter, "式", *gls_expr, "評価", *gls_eval, "REPL", *gls_repl, "演算子・被演算子", *gls_operator, "方言", *gls_hogen, "Scheme", *gls_scheme, "シンボル", *gls_symbol, "数", *gls_num, "束縛", *gls_bind, "変数", *gls_variable, "環境", *gls_env, "アトム", *gls_atom, "quote", *gls_quote, "値", *gls_value, "関数", *gls_function, "スペシャルフォーム", *gls_special, "コンス", *gls_cons, "リスト", *gls_list, "S式", *gls_sform, "番地", *gls_address, "λ山", *gls_mtlambda, "lambda", *gls_lambda, "束縛変数", *gls_bound, "次へ", *glossary_10_2, "戻る", *glossary_end
*glossary_10_2
mov %adv_tmp, 1
csel "自由変数", *gls_free, "再帰", *gls_recursion, "糖衣構文", *gls_syntaxsugar, "大域環境", *gls_globalenv, "スコープ", *gls_scope, "局所変数", *gls_localvar, "述語", *gls_predicate, "火星λ", *gls_mars, "副作用", *gls_sideeffect, "クロージャ", *gls_closure, "GC", *gls_gc, "リストの破壊的操作", *gls_listdestructive, "末尾再帰", *gls_tailrecursion, "末尾呼出", *gls_tailcall, "前へ", *glossary_10, "戻る", *glossary_end
*glossary_11
mov %adv_tmp, 0
アリサ「読みたい単語を選択してね」
csel "NScLisper", *gls_nsclisper, "Lisp", *gls_lisp, "NScripter", *gls_nscripter, "式", *gls_expr, "評価", *gls_eval, "REPL", *gls_repl, "演算子・被演算子", *gls_operator, "方言", *gls_hogen, "Scheme", *gls_scheme, "シンボル", *gls_symbol, "数", *gls_num, "束縛", *gls_bind, "変数", *gls_variable, "環境", *gls_env, "アトム", *gls_atom, "quote", *gls_quote, "値", *gls_value, "関数", *gls_function, "スペシャルフォーム", *gls_special, "コンス", *gls_cons, "リスト", *gls_list, "S式", *gls_sform, "番地", *gls_address, "λ山", *gls_mtlambda, "lambda", *gls_lambda, "束縛変数", *gls_bound, "次へ", *glossary_11_2, "戻る", *glossary_end
*glossary_11_2
mov %adv_tmp, 1
csel "自由変数", *gls_free, "再帰", *gls_recursion, "糖衣構文", *gls_syntaxsugar, "大域環境", *gls_globalenv, "スコープ", *gls_scope, "局所変数", *gls_localvar, "述語", *gls_predicate, "火星λ", *gls_mars, "副作用", *gls_sideeffect, "クロージャ", *gls_closure, "GC", *gls_gc, "リストの破壊的操作", *gls_listdestructive, "末尾再帰", *gls_tailrecursion, "末尾呼出", *gls_tailcall, "高階関数", *gls_higher, "前へ", *glossary_11, "戻る", *glossary_end
*glossary_12
mov %adv_tmp, 0
アリサ「読みたい単語を選択してね」
csel "NScLisper", *gls_nsclisper, "Lisp", *gls_lisp, "NScripter", *gls_nscripter, "式", *gls_expr, "評価", *gls_eval, "REPL", *gls_repl, "演算子・被演算子", *gls_operator, "方言", *gls_hogen, "Scheme", *gls_scheme, "シンボル", *gls_symbol, "数", *gls_num, "束縛", *gls_bind, "変数", *gls_variable, "環境", *gls_env, "アトム", *gls_atom, "quote", *gls_quote, "値", *gls_value, "関数", *gls_function, "スペシャルフォーム", *gls_special, "コンス", *gls_cons, "リスト", *gls_list, "S式", *gls_sform, "番地", *gls_address, "λ山", *gls_mtlambda, "lambda", *gls_lambda, "束縛変数", *gls_bound, "次へ", *glossary_12_2, "戻る", *glossary_end
*glossary_12_2
mov %adv_tmp, 1
csel "自由変数", *gls_free, "再帰", *gls_recursion, "糖衣構文", *gls_syntaxsugar, "大域環境", *gls_globalenv, "スコープ", *gls_scope, "局所変数", *gls_localvar, "述語", *gls_predicate, "火星λ", *gls_mars, "副作用", *gls_sideeffect, "クロージャ", *gls_closure, "GC", *gls_gc, "リストの破壊的操作", *gls_listdestructive, "末尾再帰", *gls_tailrecursion, "末尾呼出", *gls_tailcall, "高階関数", *gls_higher, "前へ", *glossary_12, "戻る", *glossary_end
*gls_nsclisper
アリサ「#FFFF33NScLisper#FFFFFFとは、2007年1月に、#FFFF33zick#FFFFFFとかいう大学生が作ったLispインタプリタよ。@/
Lispインタプリタとは、Lispというプログラミング言語で書かれたプログラムを読み取りながら、解釈し、計算をするものね。@/
本来はゲームを作るのが目的の#FFFF33NScripter#FFFFFFの上で作られているのが特徴なのよ。@/
とりあえず、何を言ってるか分からないと感じたのなら『ゲームの中に高性能電卓機能が入ってる』と考えるのもいいかもしれないわ。@/
かなり強引だけどね。@/
作った動機は特になくて『気まぐれ』だったみたいで、まさか/
NScLisperを使ってゲームを作ることになるとは思っていなかったみたい」\
goto *glossary_loop
*gls_lisp
アリサ「#FFFF33Lisp#FFFFFFとは1958年に#FFFF33John McCarthy#FFFFFFさんによって作られた#FFFF33関数型言語#FFFFFFよ。@/
関数型言語というのは、#FFFF33関数適用#FFFFFFと呼ばれる単純な手順を繰り返すことによってコンピュータに計算をさせる言語なの。@/
純粋な関数型言語は変数の値を変更することを許さないんだけど、Lispでは変数の値の変更は許されてるわ。@/
Lispはプログラムの文法が非常に単純で、それを美しいという人も多いのよ。@/
ただ、どうしても括弧が多くなるのが初心者を遠ざけるところではあるわね。@/
Lispの大きな特徴がデータとコードの区別がないというところで、これについては第4話で触れるから」\
goto *glossary_loop
*gls_nscripter
アリサ「#FFFF33NScripter#FFFFFFとは#FFFF33高橋直樹#FFFFFFさんが作った#FFFF33アドベンチャーゲーム#FFFFFFを作るためのソフトよ。@/
簡単で、多くの機能がついている上に商用利用以外は#FFFF33無料#FFFFFFなので多くの人がアドベンチャーゲームを作るのに使ってるわ。@/
用意してある命令から言って、簡単なアクションゲームを動かすことくらいなら想定されてるみたいだけど、/
さすがにプログラミング言語のインタプリタを動かすことは想定してなかったんじゃないかしら?」\
goto *glossary_loop
*gls_expr
アリサ「#FFFF33式#FFFFFFとは、#FFFF33プログラム#FFFFFFとか#FFFF33コード#FFFFFFと言われるものね。/
要するにコンピュータに指示を出すために人間が記述する文章のようなものよ。@
式は
#33FF33elm#FFFFFF
みたいな一つの要素と
#33FF33(elm1 elm2 elm3)
#FFFFFFみたいに、/
括弧の中にいくつか要素を含んだもの、
#33FF33((elm1 (elm2))(elm3))#FFFFFF
のように括弧を入れ子にしたようなものから成るわ。@/
これらの詳しい意味は第4話あたりから触れるわね」\
goto *glossary_loop
*gls_eval
アリサ「#FFFF33評価#FFFFFFとは、人が記述したプログラムである式から値を求めることで、/
プログラムを#FFFF33実行#FFFFFFすることに相当するわね。/
式を評価するとかならず#FFFF33結果#FFFFFFである#FFFF33値#FFFFFFが返ってくるというのが特徴かしら。@/
Lispは大きな式を評価するとき、小さな部分から順に評価していき、その結果を使いながら大きな式を評価するの。@/
第2話で触れるけど、
#33FF33(+ (* 3 4)8)#FFFFFF
みたいな式を書いたら、
#33FF33(* 3 4)#FFFFFF
が先に評価される。というやつね」\
goto *glossary_loop
*gls_repl
アリサ「#FFFF33REPL#FFFFFFとは#FFFF33Read-Evaluate-Print Loop#FFFFFFの略で、/
Lispインタプリタの対話形式の実行サイクルのことを指してるの。@/
対話形式ではインタプリタは、キーボードから式を#FFFF33読み込み#FFFFFF、それを#FFFF33評価#FFFFFFし、その結果を#FFFF33表示#FFFFFFするの。@/
この一連の流れのことをREPLというわ。@/
また、このことをトップレベルといったりもするわね。@/
すぐに結果が見れるから、いろいろ試すときには便利なのよ」\
goto *glossary_loop
*gls_hogen
アリサ「Lispとは元々計算のモデルを表現するために作られたもので、プログラミング言語ではなかったのよ。@/
それをMITの学生がプログラムとして実装することによって、プログラミング言語としてのLispは生まれたの。@/
その後、Lispの核となる部分は実装が簡単なため、多くの人がLispインタプリタ・コンパイラを作ったらしいわ。@/
けれど、独自拡張などによって、それぞれに違いがでたの。@/
それで、一つ一つのLispをLisp#FFFF33方言#FFFFFFというのよ。@/
現在、Lispとだけ言ったら#FFFF33CommonLisp#FFFFFFを指すことが多いわね。@/
CommonLispは多くの機能を詰め込んだLispで、非常に多機能だわ。@/
それに対して#FFFF33Scheme#FFFFFFはなるべく機能を少なくしたコンパクトな言語なのよ。@/
現在Lisp方言として使われてるのは主にこの二つね」\
goto *glossary_loop
*gls_scheme
アリサ「#FFFF33Scheme#FFFFFFとは1975年に#FFFF33Gerald J.Sussman#FFFFFFさんと/
#FFFF33Guy L.Steele Jr.#FFFFFFさんが作ったLisp方言よ。@/
#FFFF33静的スコープ#FFFFFF、#FFFF33末尾再帰の最適化#FFFFFF、#FFFF33継続#FFFFFFのサポートをしているのが特徴だけど、/
まあ、ここではそこら辺は割愛するわ。@/
とにかく重要なのは機能が極端に単純化されてるため、#FFFF33非常にシンプル#FFFFFFで、なお#FFFF33強力#FFFFFFなことよ。@/
名著『#FFFF33計算機プログラムの構造と解釈#FFFFFF』にてSchemeが使われているところから、興味を持って触る人も多いようね。@/
ちなみに、NScLisperはSchemeに近い文法だけど、厳密には違うから『SchemeライクなLisp方言』/
というのが正しいのかしら」\
goto *glossary_loop
*gls_symbol
アリサ「#FFFF33シンボル#FFFFFFは#FFFF33名前#FFFFFFを表現するためのSchemeの値よ。@/
名前とは文字の並びで、間にスペースや括弧を含めることはできないわ。/
あと、数字だけからなる場合は#FFFF33数#FFFFFFと見なされ、シンボルにはならないわ」\
goto *glossary_loop
*gls_num
アリサ「#FFFF33数#FFFFFFは数字の並びが読み込まれると作られる、Schemeの値よ。@/
本物のSchemeは/
多倍長の整数、有理数、複素数なども扱えるんだけど、NScLisperでは固定長の整数しか扱えないわ。@/
最初から巨大な数を扱えるのはなかなか爽快だから、Schemeがある程度分かってきたら、/
本物のSchemeインタプリタを使って、大きな数の階乗でも求めてみることをお勧めするわ」\
goto *glossary_loop
*gls_bind
アリサ「#FFFF33束縛(bind)する#FFFFFFとは、#FFFF33値#FFFFFFに#FFFF33名前#FFFFFFを付けることよ。@/
値とは数やシンボル等のこと。名前とはシンボルのことね。@/
具体的には#FFFF33環境#FFFFFFに値と名前の結びつきが格納されるわ。@/
単に#FFFF33束縛#FFFFFFとだけ言った場合、値と名前の結びつきのことを指すわね。@/
Schemeでは#33FF33define#FFFFFFを使うことによって新たな束縛を作ることができるわよ」\
goto *glossary_loop
*gls_variable
アリサ「#FFFF33変数#FFFFFFとは、#FFFF33値#FFFFFFと結びつけられた#FFFF33名前#FFFFFFのことね。@/
一言で言えば、#FFFF33束縛されたシンボル#FFFFFFかしら。@/
Scheme上に変数という特殊な存在があるわけではなく、/
シンボルと値の関係を保持する#FFFF33環境#FFFFFFと、/
シンボルは評価されれば対応する値になるという規則によって生まれる概念的なものね。@/
普通、束縛してないシンボルを評価すると/
『束縛されてません』と怒られるわ。@/
シンボルを評価するような式を書くと、Schemeは、そのシンボルは変数であるとみなすのよ」\
goto *glossary_loop
*gls_env
アリサ「#FFFF33環境#FFFFFFとは、#FFFF33値#FFFFFFと#FFFF33名前#FFFFFFの結びつきである/
#FFFF33束縛#FFFFFFの集まりね。@/
シンボルを評価すると、環境からそのシンボルを束縛している値を探し出し、その値を返すの。@/
最初のうちは環境の存在を意識しなくても本当は大丈夫よ。@/
Schemeの評価の規則を成す基本的な存在だから、/
リリカルLispでは詳しく書いているわ」\
goto *glossary_loop
*gls_operator
アリサ「#33FF33(式1 式2…式n)#FFFFFFのように、式の並びを括弧で囲んだ式の最初の要素#33FF33式1#FFFFFFを#FFFF33演算子#FFFFFF、@/
それ以外の要素#33FF33式2~n#FFFFFFを#FFFF33被演算子#FFFFFFというわ」\
goto *glossary_loop
*gls_atom
アリサ「括弧で囲われていない式のことを#FFFF33アトム#FFFFFFというわ。@/
具体的には数とシンボルのことね」\
goto *glossary_loop
*gls_quote
アリサ「#FFFF33quote#FFFFFFは一つの引数を受け取り、それをそのまま返すスペシャルフォームよ。@
#33FF33(quote x)#FFFFFFを評価するとシンボル#FFFF33x#FFFFFFが結果として返るわ。@/
引用符’を使うと#33FF33’x#FFFFFFと書くことができるわ」\
goto *glossary_loop
*gls_value
アリサ「#FFFF33値#FFFFFFとはLispで扱えるデータのことよ。@/
#FFFF33オブジェクト#FFFFFFということも多いわ。@/
Lispは式自身が値であり、式を評価して得られるものもまた値なの。@/
まあ、これに関しては追々説明するわね」\
goto *glossary_loop
*gls_type
アリサ「#FFFF33型#FFFFFFとは値の種類のことよ。@/
Lispの変数は任意の型の値で束縛することができるのよ」\
goto *glossary_loop
*gls_function
アリサ「#FFFF33関数#FFFFFFはいくつかの引数を受け取って、それに対して処理をし、値を返すものよ。@/
関数を呼び出すには
#33FF33(関数 引数1 引数2…引数n)#FFFFFF
と書くわ。関数はその処理をする前に、全ての引数を評価するのが特徴ね。@
#33FF33(+ 1 (* 2 3))#FFFFFFみたいな式も、同様の規則で評価されるの。@/
+から見ると、#33FF331#FFFFFFと#33FF33(* 2 3)#FFFFFFが引数だから先に評価されるのよ。@/
だから、括弧を入れ子にしても内側から評価されるのよ」\
goto *glossary_loop
*gls_special
アリサ「#FFFF33スペシャルフォーム#FFFFFFは関数と非常に良く似たものだけど、引数を評価しないのが特徴よ。@/
受け取る引数の数が決まってないものも多いわ。@/
スペシャルフォームは通常の評価とは違う特殊な規則で評価されるから注意してね」\
goto *glossary_loop
*gls_cons
アリサ「#FFFF33コンス#FFFFFFは2つの値を覚えることのできる型よ。@/
#FFFF33対#FFFFFFといったりもするわ。@/
関数consを使うことによって作り出せて、@/
関数car、cdrを使うことによって、覚えている値を取り出せるわ」\
goto *glossary_loop
*gls_list
アリサ「#FFFF33リスト#FFFFFFとは、
構造の上では『空リストか、リストをCDRに持つコンス』、@
見た目の上では『括弧の中にいくつかの値を並べたもの』と考えられるわ。@/
だから、式もまたリストなの。@/
シンボルを評価したら対応する値になるでしょ。@/
だから、シンボルそのものを取得したければquoteするわね。@/
同様に、リストは評価したら関数呼び出しとして扱われるから、/
リストそのものを取得したければquoteするのよ」\
goto *glossary_loop
*gls_sform
アリサ「#FFFF33S式#FFFFFFとは、
1.アトム
2.(S式 . S式)
のことよ。@例えば、
#33FF3311#FFFFFF
#33FF33s#FFFFFF
#33FF33(s . 11)#FFFFFF
#33FF33(t . (s . 11))#FFFFFF
のことね」\
アリサ「ただし、
#33FF33(A .(B .(C .D)))#FFFFFF
というS式は、書き方を省略して、
#33FF33(A B C . D)#FFFFFF
と書くことができるわ。@/
また、Dが空リスト#33FF33()#FFFFFFの場合、さらに省略して、
#33FF33(A B C)#FFFFFF
と書くことができるの。@/
ただし、これはあくまでも書き方を省略したもので、どちらで書いても問題ないわ」\
アリサ「Lispの大きな特徴は、プログラムである式が全てS式で表現できて、@/
それを評価したものを表示するときも、すべてS式を使って表示できるということなの。@/
ただし、一部の値の表示はS式以外の表現で表されるわ。@/
だから、入力の形式と出力の形式が完全に一致するわけではないのよ」\
goto *glossary_loop
*gls_address
アリサ「Lispの値は箱の中に入っていると考えられるの。@/
この箱はたくさん用意されているけど、一つ一つ固有の番号が付いていて、/
その番号のことを#FFFF33番地#FFFFFF(Address)というの。@/
この『箱』とは何かといったら、実際はメモリなど、計算機の記憶装置よ。@/
ちなみに、この番地という言葉、実は正しいLisp用語ではないの。@/
あんまり外では言わないほうがいいわよ」\
goto *glossary_loop
*gls_mtlambda
アリサ「#FFFF33λ山#FFFFFFとは、京都の東山に位置しており、五山送り火で有名な山よ。@/
何故山にλと描かれているのかはよく分かってないの。@/
よく晴れた日にはλの文字が『大』の文字にも見えるのよ」\
goto *glossary_loop
*gls_lambda
アリサ「関数を作るのになんで#33FF33lambda#FFFFFFという/
名前?と思うかもしれないわね。@/
気になった人は、#FFFF33λ計算#FFFFFFを勉強してみるといいわ。@/
『計算論 計算可能性とラムダ計算』という本がお勧めよ。@/
λ計算を勉強すると、改めてLispの面白さが分かると思うわ」\
goto *glossary_loop
*gls_bound
アリサ「束縛変数とは、仮引数のことよ。@
#33FF33/
(lambda (x) 本体)#FFFFFF
この式の値として得られる関数に対してxのことを束縛変数といい、/
xはこの関数に束縛されているというわ。@/
束縛変数の値は関数を呼び出すときに付けた実引数の値になるわ。@/
だから、束縛変数は名前を#33FF33本体#FFFFFFに出てこない別の名前に付け替えても、関数の働き自体は全く変わらないわ」\
goto *glossary_loop
*gls_free
アリサ「#FFFF33自由変数#FFFFFFとは関数本体に出てくる束縛変数以外の変数のことよ。@
#33FF33/
(lambda (x) (+ x y))#FFFFFF
この式の値として得られる関数に現れる変数yが自由変数よ。@/
自由変数の値はその式を評価した環境によって決まるわ。@/
だから、自由変数を含む関数は同じ実引数をつけても違う値が返ることがあるわ」\
goto *glossary_loop
*gls_recursion
アリサ「#FFFF33再帰#FFFFFFとは自分のことを定義するのに自分自身を使うことよ。@
#33FF33/
(define f
 (lambda (n)
  (if (= n 0)
      0
      (f (- n 1)))))#FFFFFF
例えば、この式はfを定義してるのに、その値である関数は中でfを使ってるでしょ。@/
関数呼び出しとして自分自身を呼び出すことを#FFFF33再帰呼び出し#FFFFFFというわ」\
goto *glossary_loop
*gls_syntaxsugar
アリサ「#FFFF33糖衣構文#FFFFFF(Syntax Sugar)とは、/
既にある構文で実現できることを簡単に実現するために用意されている特殊な構文のことよ。@/
特定の用途に限定された構文だけあって、上手く使えば式の見通しはよくなるわ。@/
糖衣構文は言語の本質からは遠い構文だけど、人間の感覚には近い構文なの」\
goto *glossary_loop
*gls_scope
アリサ「#FFFF33スコープ#FFFFFFとは変数が見える範囲のことよ。@/
SchemeやCommonLispは#FFFF33レキシカルスコープ#FFFFFFといって、/
内側から外側が見えるけど、外側からは内側が見えないのよ。@/
show_dgm ":l;img/dgm_gls_scope01.bmp"
Lisp方言によっては、これとは異なる#FFFF33ダイナミックスコープ#FFFFFFというものを採用しているものもあるわ」\
csp SP_DGM0 : print E_FAST
goto *glossary_loop
*gls_localvar
アリサ「局所変数とはある特定の範囲でだけ使える変数のことよ。@/
Lispで局所変数を作るにはlambdaか、その糖衣構文であるletを使うわ」\
goto *glossary_loop
*gls_globalenv
アリサ「#FFFF33大域環境#FFFFFFとはトップレベルから入力された式を評価するのに使われる環境よ。@/
新たな環境が作られても、最終的には大域環境に繋がるから、/
大域環境に含まれている#FFFF33大域変数#FFFFFFは、どこからでも見ることができるわ」\
goto *glossary_loop
*gls_predicate
アリサ「#FFFF33述語#FFFFFFとは#33FF33#t#FFFFFFか#33FF33#f#FFFFFFを返す関数よ。@/
#33FF33number?#FFFFFFや#33FF33symbol?#FFFFFFのように、基本的には名前の最後に『?』がつくのよ。@/
ただ、#33FF33=#FFFFFFのように『?』で終わらない名前のものもあるけどね。@/
この『?』は『ピー』と発音するわ。述語(predicate)の頭文字なの。@/
Scheme以外のLisp方言では、キーボードから『?』を打ち込めない機種が存在したという歴史的経緯から、/
#33FF33numberp#FFFFFFのように、述語の最後がpで終わってるものも多いわ」\
goto *glossary_loop
*gls_mars
アリサ「ググれ!」\
アリサ「といいたいところだけど、URLを載せておくわね。
#FFFF33http://themis.asu.edu/zoom-20040202A#FFFFFF
きっと衝撃的な画像を目にすることになるわよ」\
goto *glossary_loop
*gls_sideeffect
アリサ「#FFFF33副作用#FFFFFFとは結果となる値を求めるのではなく、ほかの事をするための作用のことよ。@/
例えば、変数の値を変更したり、文字を表示したりするのがこれに相当するわ」\
goto *glossary_loop
*gls_closure
アリサ「#FFFF33クロージャ#FFFFFF(関数閉包)とは、関数の中身と評価に使う環境を一緒にしたものよ。@/
環境を一緒にすることによって、自由変数の値を取得することができるの。@/
Schemeではlambdaによって作られる関数型の値はクロージャだから、特にこの言葉を気にしなくてもいいわよ」\
goto *glossary_loop
*gls_gc
アリサ「#FFFF33GC#FFFFFF(Garbage Collection)とは/
必要のなくなった値の入った箱から値を捨て、その箱を再利用する仕組みのことよ。@/
Lisp処理系はGCを搭載しているので、プログラマが必要な値、必要でない値の判別をする必要がなくなり、/
楽ができるのよ」\
goto *glossary_loop
*gls_listdestructive
;;図が欲しい
アリサ「#FFFF33リストの破壊的操作#FFFFFFとは、コンスの中身を書き換える操作のことよ。@/
#33FF33set-car!#FFFFFF、#33FF33set-cdr!#FFFFFFを使うことによって行うわ。@/
リストの破壊的操作は循環構造を作る場合もあるの。@/
show_dgm ":l;img/dgm_gls_listdestructive01.bmp"
csp SP_DGM0 : print E_FAST
NScLisperは循環構造を持つリストを表示しようとすると無限ループに陥るし、/
慣れないうちは使わない方がいいわよ」\
goto *glossary_loop
*gls_tailrecursion
アリサ「#FFFF33末尾再帰#FFFFFFとは関数の最後で行う再帰呼び出しのことよ。@/
関数の最後とは、その式の値がそのまま関数の返す値となる箇所のことなの。
Lispで末尾再帰を行うと、それは自動的に関数呼び出しではなく、単純な繰り返しに変換されるから、@/
無駄にメモリを使うことなく、高速に処理をおこうなうことができるのよ」\
goto *glossary_loop
*gls_tailcall
アリサ「#FFFF33末尾呼出#FFFFFFとは関数の最後で行う関数呼び出しのことよ。@/
Schemeは末尾再帰を単純な繰り返しに変換するのと同様に、末尾呼出も繰り返しに変換するのよ」\
goto *glossary_loop
*gls_higher
アリサ「#FFFF33高階関数#FFFFFFとは受け取る引数や、返す値が関数である関数のことよ。@/
この高階関数を簡単に扱えるのがLispの大きな特徴の一つなの。@/
高階関数を使ったテクニックなどを勉強したかったら、ちゃんとした本でLispを勉強してね」\
goto *glossary_loop