Archive for the ‘car’ Tag

first, second, third 、、、

 newLISP には、first は有りますが、second, third 等はありません。
 別に無くても、インデックス機能があるので、要らないのですが、困ったこともあります。

> ('(0 1 2) 2)
2
> ('(0 1) 2)

ERR: list index out of bounds
> 

 こんな風に、範囲外を指定するとエラーになります。最初に length でリストの大きさを調べるか、catchthrow の組み合わせれば良いのですが、結構手間なので、私は“newlisp-utility.lsp”で次のように登録して、使っています。

(define cdr    (fn (lst) (or (rest lst) nil)))
(define car    (fn (lst) (if (empty? lst) nil (first lst))))
(define second (fn (lst) (first (or (rest lst) '(nil)))))
(define third  (fn (lst) (first (or (rest (rest lst)) '(nil)))))
(define fourth (fn (lst) (first (or (rest (rest (rest lst))) '(nil)))))

 これなら、

> (third '(1 2 3))
3
> (third '(1 2))
nil
> 

 こんな感じで、範囲外は nil になってくれます。
 また、carcdr は、引数が空リスト () の時、nil が返ります。私のスクリプトで、時々、carcdr を使っているのは、そういう効果を期待していたりします。
 さて今回、carcdr 共に、second 以下を一新しました。

(define cdr    (fn (lst) (if-not (nil? lst) (or (rest lst) nil))))
(define car    (fn (lst) (first (or lst '(nil)))))
(define second (fn (lst) (car (cdr lst))))
(define third  (fn (lst) (car (cdr (cdr lst)))))
(define fourth (fn (lst) (car (cdr (cdr (cdr lst))))))

 変更点は、上記関数の引数が nil の時でも、nil を返すようにしたこと。
 と言うことで、またまた、ですが、“newlisp-utility.lsp”のアップデートです(笑)。

 以上、如何でしょうか?

広告

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 の両方を使い分けているのは、こういう理由だったりします(笑)。

 以上、如何でしょうか?