newLISP のnil と 空リスト()

 “newLISP で On Lisp する...第20章(その1)...または、newLISP と scheme の違い” でも書いていますが、newLISP では nil と 空リスト () は別のものです。
 実際、マニュアルには、

newLISP では、nil と空リスト () は、他の Lisp のように同じではありません。条件式、and, or, if, while, unless, until, cond、においてのみ、それらはブールの偽として扱われます。

In newLISP, nil and the empty list () are not the same as in some other Lisps. Only in conditional expressions are they treated as a Boolean false, as in and, or, if, while, unless, until, and cond.

 とあります。
 つまり、空リストは、フロー制御式の条件式においては nil ですが、それ以外の組込関数では、true 相当です。
 ここで、フロー制御式には、do-whiledo-until も含まれます。
 それ以外では、true 相当ですから、例えば、組込filterclean で、

> (map rest '((a b) (a) ()))
((b) () ())
> (filter rest '((a b) (a) ()))
((a b) (a) ())
> (clean rest '((a b) (a) ()))
()
>

 となります。これは、以前、私が使い方を間違えた例です(汗)。
 組込filter は、第一引数の関数を第二引数のリストの項目に適用して、true に評価されるものを取り除きます。組込clean は、逆に残します。これらの関数では、空リストは true 相当ですから、上記のような結果になったわけです。
 ここでは、次のようにして、空リストを nil にすべきだったのです。

> (map rest '((a b) (a) ()))
((b) () ())
> (filter (fn (x) (or (rest x) nil)) '((a b) (a) ()))
((a b))
> (clean (fn (x) (or (rest x) nil)) '((a b) (a) ()))
((a) ())
> 

 ここで、使っているラムダ式は、newlisp-utility.lsp で定義している cdr と同じです。

> cdr
(lambda (lst) (or (rest lst) nil))
>

 引数が空リストなら、マニュアルにあるように組込or では、空リストは、nil 相当ですから、次の項目に進み、nil が返ります。
 ちなみに、newlisp-utility.lsp で定義している car は、

> car
(lambda (lst) 
 (if (empty? lst) 
  nil 
  (first lst)))
> (car '())
nil
> 

 としています。空リストに組込first を適用するとエラーですから。
 “newLISP で On Lisp する”で、car と first、cdr と rest の両方を使い分けているのは、こういう理由だったりします(笑)。

 以上、如何でしょうか?

No comments yet

コメントを残す