value関数(その3)

それじゃ、id:yagiey:20081114で紹介した6種類のアクションを実装していくことにする。
まずは*const関数。(半角のアステリスク記号は、はてな記法に解釈されるため、ソースコード以外の箇所では全角文字で表記)
早速定義を示すと、

(define *const
  (lambda (e table)
    (cond
     ((number? e) e)
     ((eq? e #t) #t)
     ((eq? e #f) #f)
     (else (build 'primitive e)))))

*const関数は、atom-to-action関数の定義より、以下のアトムに対して返される関数。

  • 数値
  • #t
  • #f
  • cons
  • car
  • cdr
  • null?
  • eq?
  • atom?
  • zero?
  • add1
  • sub1
  • number?

つまり、リテラル(って言って良いのかな?)と組込み関数にマッチする関数。
どれを組込み関数にするかは、実装者が決める。ここでは、cons以下の10個の関数を組み込み関数としている。
リテラルの場合はその値を返し、関数ならば

(primitive 関数名)

というリストを返す。
このリストがどう使われるのかは後ほど。
また、この関数は第2引数のテーブルを使用する必要がない。


次に、*identifier関数。
こいつの定義は以下

(define *identifier
  (lambda (e table)
    (lookup-in-table e table initial-table)))
    
(define initial-table
  (lambda (name) (car '())))

*identifier関数は、atom-to-action関数の定義により、識別子にマッチする。
つまり、そのアトムが何かを指し示す名前だった場合にマッチ。
戻り値は、名前が示す値。それを探すのに第2引数のテーブルを使用する。
initial-table関数は、テーブルの中に名前が見つからなかったときに評価される関数。
上の定義だと、必ず実行時エラーで以上終了するようになっている。


これ以降はlist-to-actionから返されるアクション。
最初は*quote。定義は以下。

(define *quote
  (lambda (e table) (text-of e)))

(define text-of second)

これは簡単ね。
リストeの先頭はアトムで、かつ、それがquoteだって分かっているので、eの2番目のS式が返すべき値。


次は*lambda関数。定義は以下。

(define *lambda
  (lambda (e table)
    (build 'non-primitive
           (cons table (cdr e)))))

こいつはlambda式にマッチする。
でも、パッと見、返す値は複雑でよく分からん。
そんなときは、実際にやってみよう。

(*lambda
  '(lambda (x) (add1 x)) '())

の結果は、

(non-primitive
  (()
   (x)
   (add1 x)))

だと。このリストがどう使われるかは後ほど。
ちなみに、このリストにsecondを適用した結果のリストはclosure recordと呼ばれるそうな。
んで、closure recordから1番目、2番目、3番目のS式を取り出すリストをそれぞれ

(define table-of first)
(define formals-of second)
(define body-of third)

と定義してる。


次は*cond関数。定義は以下。

(define *cond
  (lambda (e table)
    (evcon (cond-lines-of e) table)))

(define evcon
  (lambda (lines table)
    (cond
     ((else? (question-of (car lines))
      (meaning (answer-of (car lines)) table))
     ((meaning (question-of (car lines)) table)
      (meaning (answer-of (car lines)) table))
     (else
      (evcon (cdr lines) table)))))

(define cond-lines-of cdr)

(define else?
  (lambda (x)
    (cond
     ((atom? x) (eq? x 'else))
     (else #f))))

;; (S式1 S式2)からS式1とS式2を取り出す補助関数2個
(define question-of first)
(define answer-of second)

*cond関数はcondによる条件分岐を処理するためのアクション。
補助関数がいくつもあってややこしいな。
...そんな時は実際にやってみればおk。

(*cond
  '(cond
    (coffee klatsch)
    (else party))
  '(((coffee) (#t))
    ((klatsch party) (5 (6)))))

を実際にやってみよう(面倒くさいから書かんけど
答えは5ね。
テーブルは、evcon関数で条件などを評価するためにmeaning関数を使用するから必要。


今日はここまで。
次回は*application関数。