Scheme手習い Chapter 10

ついに10章まで来てしまった。この章で最後。手習いを終えたら修行が待っている。
いつも通り読みながらの気づき等

読みながらのメモ

  • エントリ(entry)とは(集合のリスト ←と同じ長さの値のリスト)のペア
  • (new-entry setl l)でエントリを作れる
  • lookup-in-entryはnameとentryとentry-fを取る
    • entryの名前の集合からnameを探して対応する値を返す
    • entryの中でnameが見つから無かった時はentry-fにnameを渡して呼び出す
    • entryをnamesとvaluesに分解して、lookup-in-entry-helpを呼んでいる
  • テーブル(table)はエントリ(entry)のリスト
    • 環境ともいう
  • extend-tableはエントリを古いテーブルの先頭に付け加え、新しいテーブルを作る
  • lookup-in-tableはnameとtableとtable-fを取る
    • テーブルの中の先頭のエントリから順にnameの値を探して対応する値を返す
    • tableの中でnameが見つから無かった時はtable-fにnameを渡して呼び出す
    • tableから先頭のエントリを取り出してlookup-in-entryを呼んでいる
    • 先頭のエントリの中でnameが見つからなかった時に次のエントリを探せるように、entry-fにtableへの参照を持ったクロージャを渡している
  • 式(Expression)
    • eはexpressionの略
    • タイプが6つある
    • *const
    • *quote
    • *identifier
    • *lambda
    • *cond
    • *application
    • タイプを関数、actionとして表現する
    • 8章のatom-to-functionのようにexpression-to-actionを定義
    • atomならatom-to-action
    • listならlist-to-action
      • carを見て判断
  • expression-to-actionがきちんと動作するならvalueとmeaningを定義出来る
  • valueSchemeのevalと同じ。引数で式を取る
    • meaningに式と空の環境を渡して呼び出す
  • meaningは式と環境を引数に取る
    • expression-to-actionでタイプの表現、関数を取り出す
    • 式と環境を渡しその関数を呼び出す
  • タイプを表現するアクション達
  • 非基本関数と基本関数
    • 基本関数は何をするものか知っている関数
    • 非基本関数は引数と関数本体によって定義される関数
    • 仮引数と関数本体を覚えておく必要がある。
    • (lambda (x) x)でいうcdrの((x) x)の部分
    • それに加えテーブルを覚えておく。
    • この3つでクロージャレコード
  • evcon
    • null?の質問がないまま再帰しているのでquestion-ofが真になるlineが無かったらエラーが出るため、少なくとも1つの質問は真である必要がある。
  • evlis
    • listの全ての意味をmeaningで求めて新しいlistにして返す、のかな
  • apply
    • primitiveかそうでないか、でapply-primitiveとapply-closureに処理を振り分けてる。

気づき疑問等

  • extend-tableで新しいエントリを先頭につけるのは、carを使って先頭から探るため?
  • p183のadd1?sub1?はadd1、sub1の間違い?
  • *identifierの中のinitial-tableは…
  • evconはeval-condの略?
  • evlisはeval-list?
  • :atom?をatom?だと思っててハマった orz
  • あと:atom?がキーワードとして認識されちゃったのでmy-atom?に変更
  • ページの順番通りに*applicationを定義した後applyを定義してハマった。
    • 最初に*applicationを定義する時、中でapplyを使ってる
    • 自前applyを定義する前に*applicationを定義するとGaucheに元からあるapplyを見ちゃう
    • 自前applyを定義するのを*applicationの前にもってきて解決
  • defineが出てきてないのに「再帰はYコンビネータによって得られるので、必要はありません。」という答え方は素敵だと思った
    • 全部lambdaで書けばdefine使わなくてok的な
    • でも「Scheme修行も見てください。」とのこと。
  • 「Yコンビネータによる変形を行うとインタプリタ上でインタプリタを走らせる事が可能である」
    • 前の章で出てきたYコンビネータがしっかりとインタプリタで動く事を確認してちょっと感動。動きを追ってみたい。
    • loopはYコンビネータで出来るし、evalは今作った。後はreadとprintだけ用意してやればREPLが出来る!?

感想

最後の章でもapplyのところで処理を分けたり、table関連でうまく抽象化しててすごく分かりやすい。
lookup-in-tableの中でlookup-in-entryに渡すentry-fのクロージャ(cdr table)の部分が好き。

(lambda (name)
  (lookup-in-table name (cdr table) table-f))

この10章だけでも何回も読めそう。
冒頭にある読者へのガイドラインでは

急いでこの本を読まないでほしい。注意深く読むこと。有益なヒントがテキスト全体にちりばめてある。この本を2回以下で読み切ろうとしないこと。系統的に読むこと。ある章が完全には理解できなければ、次の章はもっと理解できなくなる。質問はだんだん難しくなるように並べてある。前の方が解けないと、後ろのほうはもっと難しい。

と書いてあるけど、もう一周読んでみても楽しめそうです。
前半部分は何度も読んでるけど8, 9, 10とそこらへんは理解度足りてない感じもするのでもうちょい読み込む予定…
最初にエントリをあげたのが2011年4月14日で、今は8月10だから大体4ヶ月ほど。
特にYコンビネータのところでコミットの感覚が20日以上あいてるのでそこが一番難しかったような。
前の方から後ろに行けばいくほど楽しかったです。