Archive for the ‘aif2’ Tag

newLISP で On Lisp する...第14章(その2)

(この blog は、“short short story または 晴耕雨読な日々”からの引越してきたもの。スクリプトは、newLISP V10.2.1 以降で動作するように書き直しています。
defun 等の newLISP組込関数に無い関数は、特に断らない限り、newlisp-utility.lsponnewlisp.lsp に定義してあります。)

 今回は、第14章 アナフォリックマクロ失敗 から、シンボル nil について(cdr は、newlisp-utility.lsp に定義してあります)、

> (cdr '(a))
()
> cdr
rest<406AFE>
> (rest '(a))
()
> 

 newLISP では、空リストが nil ではありませんが、

> (not (rest '(a)))
true
> (if (rest '(a)) "true" "nil")
"nil"
> 

 if 文では、偽(true の逆)として扱われます。

> (= 1 0)
nil
> 

 そして、述語で偽(true の逆)は nil になります。
 newLISP に find-if は、ありませんが、前回定義した find-if を使えば(oddp と null は、newlisp-utility.lsp に定義してあります)、

> find-if
(lambda (func lst) 
 (let (it (find nil lst (lambda (x y) (func y)))) 
  (if it 
   (lst it) B)))
> (find-if oddp '(2 4 6))
nil
> (find-if null '(2 nil 6))
nil
> 

 関数 find-if は、失敗を nil で表します。上の例で、検索したものが nil の場合、見分けが付きません。
 しかし、newLISP の組込関数で、失敗以外で nil を返すのは、驚くほど少ないのです。

> (find nil '(2 4 6) (fn (x y) (oddp y)))
nil
> (find nil '(2 nil 6) (fn (x y) (null? y)))
1
> 

 組込find は、検索しますが、戻り値は、リストの位置です。nil が返ったら間違いなく失敗です。
 例外は、firstnth 。しかし、これらは、失敗で nil を返すことはありません。エラーですから(苦)。newLISP の組込関数の少なさは、ここまで配慮されて、慎重に選ばれた結果なのかもしれません。
 また、newLISP には、ドット対がないので

> (setq synonyms '((yes ture)(no nil)))
((yes ture) (no nil))
> (assoc 'no synonyms)
(no nil)
> (setq synonyms '((yes ture)(no)))
((yes ture) (no))
> (assoc 'no synonyms)
(no)
> (assoc 'maybe synonyms)
nil
> 

 と、なります。前回使ったnewLISP組込lookup は、検索の失敗と、検索したものが nil だった場合が同一になる稀有の例かもしれません。

> (setq synonyms '((yes ture)(no nil)))
((yes ture) (no nil))
> (lookup 'yes synonyms 1)
ture
> (lookup 'no synonyms 1)
nil
> (lookup 'maybe synonyms 1 'N/A)
N/A
> 

 それでも、上記のように、検索失敗時に返すシンボルを指定することで、回避できます。
 この手のオプションは、Common Lisp の多くの組込アクセス関数に備わっています。find-if に付いていないのは、むしろ例外? だから、“On Lisp”本書の例としては、取り上げられた?
 また、newLISP には、member-if がありませんが、本書程度の例なら、組込member を使って

> (member nil '(2 nil 6))
(nil 6)
> 

 となり、曖昧さは排除できます。
 そして、多値
 newLISP には、多値も無く、hash も gethash もありませんが、nii と空リストは異なりcontext があります。

> (new Tree 'edible)
edible
> (edible "olive-oil" true)
true
> (edible "motor-oil" '())
()
> (edible "olive-oil")
true
> (edible "motor-oil")
()

 3通りを判別する関数は(defun は、newlisp-utility.lsp に定義してあります)、

(defun edible? (x)
  (let (val (edible x))
    (if val 
        'yes
      (if (nil? val) 'maybe 'no))))

 となり、

> (map edible? '("motor-oil" "olive-oil" "iguana"))
(no yes maybe)

 動作は、“On Lisp”本書と同じように見えます。
 get も newLISP にはありませんが、ここでは定義しません。
 多値を返すアナフォリックマクロ の実装に入ります。とはいっても、newLISP には、多値はありませんので、前に実装したものを使います。gethash のような多値を返す関数の無いnewLISP では、あまり意味がありませんけど。
 まず aif2 から(multiple-value-bind は、onnewlisp.lsp に定義してあります)、

(define-macro (aif2)
; (aif2 test &optional then else)
  (letex (_win (gensym)
          _test (args 0)
          _then (second (args))
          _else (third (args)))
    (multiple-value-bind (it _win) _test
       (if (or it _win) _then _else))))

 動作確認用に多値を返す gethash を用意します(values は、onnewlisp.lsp に定義してあります)。

(defun gethash (key ctx)
  (aif (ctx (term key))
      (values it true)
    (if (nil? it)
        (values nil nil)
      (values it true))))

 そして、前述の edible? は、次のように書けます。

(defun edible2? (x)
  (aif2 (gethash x edible)
           (if it 'yes 'no)
           'maybe))

 動作はというと、

> (map edible2? '(motor-oil olive-oil iguana))
(no yes maybe)
> 

 見た目は、edible? と変わりませんけどね(笑)。

 さて、長くなってきたので、多値を返すアナフォリックマクロ の残りからは、次回以降に。

 以上、如何でしょうか?

広告