EoPL reading (55) 2.2 An Abstraction for Inductive Data Type

述語な手続きを確認。
ってその前に以下って何だ、と

       (define Type-name
         (cons '(Variant-name ...)
           '((Variant-name Field-name ...) ...)))

gosh で確認。

$ gosh
gosh> (add-load-path ".")
("." "/usr/share/gauche/site/lib" "/usr/share/gauche/0.8.13/lib")
gosh> (load "define-datatype")
define-datatype.scm version J3 2002-01-02 10:55
#t
gosh> (define-datatype bintree bintree?
  (leaf-node
   (datum number?))
  (interior-node
   (key symbol?)
   (left bintree?)
   (right bintree?)))
interior-node
gosh> bintree
((leaf-node interior-node) (leaf-node datum) (interior-node key left right))
gosh> 

なるほど。確かにそうなってますね。で、次の述語ですが定義の先頭部分が以下。

       (define Type-name?
         (if (symbol? 'Type-name)
           (lambda args
             (if (null? args)
               (define-datatype:report-error 'Type-name? "expects 1 argument, not 0.")

Type-name が symbol じゃないケイスってどうなるのか、と言いつつ以下

gosh> (define-datatype "xxx" bintree?
  (leaf-node
   (datum number?))
  (interior-node
   (key symbol?)
   (left bintree?)
   (right bintree?)))
*** ERROR: Compile Error: syntax-error: (#<identifier user#define> "xxx" (#<identifier user#cons> (#0=#<identifier user#quote> (leaf-node interior-node)) (#0# ((leaf-node datum) (interior-node key left right)))))
"(stdin)":11:(define-datatype "xxx" bintree? (lea ...

Stack Trace:
_______________________________________
gosh>

これって上記の

((leaf-node interior-node) (leaf-node datum) (interior-node key left right))

なリストを "xxx" の束縛させようとしてエラーになっているように見えます。scheme って symbol 以外のものにオブジェクトの束縛を、なソレって文法エラーなレベルなのであれば

       (define Type-name?
         (if (symbol? 'Type-name)
           (lambda args
             (if (null? args)

上記のエラーチェックな分岐は不要なのでしょうか。うーん。

とりあえず

ここはスルーでそれ以降のナニを確認。まずここ

             (if (null? args)
               (define-datatype:report-error 'Type-name? "expects 1 argument, not 0.")

定義が

       (define Type-name?
         (if (symbol? 'Type-name)
           (lambda args

ってなっているので args が null ってのは引数が無い場合、と。一応 gosh にて確認。

gosh> (define f (lambda args args))
f
gosh> (f)
()
gosh> (f 1)
(1)
gosh> 

ふむふむ。通常 (lambda (args) とかってヤるので最初戸惑いました。あるいは直後に

               (if (null? (cdr args))

というチェキが入ってます。これは引数一つ限定ね、な確認な模様。

gosh> (cdr (f 1))
()
gosh> (cdr (f 1 2 3))
(2 3)
gosh> 

一つなら '() ですが、それ以外はそうでない、と。で、引数一つが確認できたら

                 (let ((variant (car args)))
                   (let ((type-info Type-name)) 
                     (if (and (pair? type-info) (list? (car type-info)))
                       (and (pair? variant)
                         (memq (car variant) (car type-info)) #t)

がある意味本体。なるほど、bintree なオブジェクトの car 要素は

  • leaf-node
  • interior-node

しか無いですね。なんつーか凄いな。とりあえずここまでの試験を書いてもう少し読み進めて cases を確認、な方向で。

試験書いてみる

上記のナニで言えば

(test* "predicate procedure needs 1 argument"
       *test-error*
       (bintree?))

引数ナシの述語はダウト。結果が以下 (一部のみ

test predicate procedure needs 1 argument, expects #<error> ==> ok

あるいは

(test* "predicate procedure needs 1 argument"
       *test-error*
       (bintree? 1 2))

同様にパス。

test predicate procedure needs 1 argument, expects #<error> ==> ok

あるいは引数がペアじゃないと駄目。

(test* "predicate procedure needs pair"
       *test-error*
       (bintree? 1))

これは駄目でした。引数一つでもペアになるのか。

$ make
Testing define-datatype ...                                      failed.
discrepancies found.  Errors are:
test predicate procedure needs pair: expects #<error> => got #f
$

あ、違うや。

                     (if (and (pair? type-info) (list? (car type-info)))

な条件がダウトなのか。あ、違う。逆か。ここは bintree? とか使ってしまうと自動でパスしてしまうのか。どうやってここをパスしない試験を書けば良いのかが微妙。
で、最後の

                       (and (pair? variant)
                         (memq (car variant) (car type-info)) #t)

は明日確認します。