numbered?とvalue

算術式と算術式の表現

今日から6章だ。算術式と、算術式の表現という言葉が出てきた。算術式とは(数を含む)アトムか、2つの算術式を+か×か↑で結合したもの。一方、算術式の表現とは算術式を括弧でくくったものだ。
例を示そう。まずは算術式の例:

  • 1
  • 1 + 3
  • 1 + 3 × 4
  • 3 ↑ y + 5

ここで注意しておかなきゃいけないのは、+や×、↑ はアトムであって前に書いた演算子(o+とかo*とか書いたやつ)ではないってこと。
それから算術式の表現の例:

  • 1
  • (1 + 3)
  • (1 + (3 × 4))
  • ((3 ↑ y) + 5)

ポイントは、括弧でくくったことでS式になったところだ。1 はアトムなので括弧でくくらなくてもS式だ。算術式がS式になったことで Scheme で扱えるようになった。

numbered?

関数 numbered? は算術式の表現、つまりS式が、+、×、↑ を除いて数だけを含むかどうかを判定する関数。特殊文字は使えないので、これからは e+、e*、e^ (e は expression の e)と書こう。
p.101 にヒントがあるので、numbered? を書いてみよう。

(use mymodule)

(define numbered?
  (lambda (aexp)
    (cond
      ((atom? aexp) (number? aexp))
      ((eq? (car (cdr aexp)) (quote e+))
        (and (numbered? (car aexp)) (numbered? (car (cdr (cdr aexp))))))
      ((eq? (car (cdr aexp)) (quote e*))
        (and (numbered? (car aexp)) (numbered? (car (cdr (cdr aexp))))))
      (else
        (and (numbered? (car aexp)) (numbered? (car (cdr (cdr aexp)))))))))

(print (numbered? 1))
(print (numbered? '(1 e+ 3)))
(print (numbered? '(1 e+ (3 e* 4))))
(print (numbered? '((3 e^ 2) e+ 5)))

実行してみよう:

^o^ > gosh -I. numbered.scm
#t
#t
#t
#t

うまくいったようだ。

value

関数 value は算術式の自然な値を返す関数。たとえば (value (1 e+ 2)) は 3 を返す。これもヒントを見ながら書いてみよう。

(use mymodule)

(define value
  (lambda (nexp)
    (cond
      ((atom? nexp) nexp)
      ((eq? (car (cdr nexp)) (quote e+))
        (o+ (value (car nexp)) (value (car (cdr (cdr nexp))))))
      ((eq? (car (cdr nexp)) (quote e*))
        (o* (value (car nexp)) (value (car (cdr (cdr nexp))))))
      (else
        (o^ (value (car nexp)) (value (car (cdr (cdr nexp)))))))))

(print (value 1))
(print (value '(1 e+ 3)))
(print (value '(1 e+ (3 e* 4))))
(print (value '((3 e^ 2) e+ 5)))

実行:

^o^ > gosh -I. value.scm
1
4
13
14

OKだ。

numbered?とvalueに共通すること

2つの関数、numbered? と value に共通するのは、引数がアトムでなかった場合、算術式の2つの部分式について再帰するところだ。部分式が算術式であるかどうかがわかれば全体が算術式であるかどうかもわかるし、部分式の値がわかれば全体の値もわかる。

第7の戒律
性質を同じくするすべての構成部分について再帰すべし。

  • リストのすべての部分リストについて。
  • 算術式のすべての部分式について。