Archive for 2010年6月22日|Daily archive page
newLISP で On Lisp する...第3章(その2)
第3章 関数プログラミング の続きです。
今回は、命令型プログラミングの裏返し から。
newLISP も Common Lisp と同様に、関数型プログラミングと命令型プログラミングの両方で書くことができます。
(defun、car は、newlisp-utility.lsp に定義してあります)
(defun fun (x) (list 'a (pow (car x) 2))) (defun imp (x) (local (y sqr) (setq y (car x)) (setq sqr (pow y 2)) (list 'a sqr)))
組込local は、len と同じ機能で、引数のシンボルを全て nil で初期化します。
“On Lisp” 本書にある命令型プログラムを裏返しながら関数型プログラムへ変更していく過程は、newLISP でも一緒です。
動作は、試すまでも無いですね。
次の 関数的インターフェイス にある副作用の問題は、newLISP では当てはまらないかもしれません。
最初の二つの例は、
(defun qualify (expr) (nconc (copy expr) (list 'maybe))) (context 'total) (setq x 0) (defun total:total (y) (++ x y)) (context MAIN)
となり、動作は、
> (qualify '(x)) (x maybe) > (total 1) 1 > (total 3) 4 > (total 5) 9
こんな感じ。
そして、nconc の使い方、
(nconc は、第3章(その1) で定義しています)
(defun ok (x) (nconc (list 'a x) (list 'c))) (defun not-ok (x) (nconc (list 'a) x (list 'c)))
の動作は、
> (setq x '(b)) (b) > (ok x) (a (b) c) > x (b) > (not-ok x) (a b c) > x (b)
どちらも、引数に副作用を及ぼしません。
前回書きましたように、newLISP では、通常、副作用を起こす関数は定義できないからです。
“通常”としたのは、特殊な方法で書くこともできるからで、それはまた別の機会に。
もちろん、
(defun anything (x) (+ x *anything*))
も副作用は起こしませんし、
(defun exclaim (expression) (append expression '(oh my)))
を使って、
> (exclaim '(lions and tigers and bears)) (lions and tigers and bears oh my) > (extend (exclaim '(lions and tigers and bears)) '(goodness)) (lions and tigers and bears oh my goodness) > (exclaim '(fixnums and bignums and floats)) (fixnums and bignums and floats oh my)
としても、Common Lispのような副作用は起きません。
もちろん、
(defun exclaim (expression) (append expression (list 'oh 'my)))
でも、問題はありません。すべて、マクロでなく関数定義だからです。
関数がクォート付きリストを返すべきでないというルールは、newLISPでは、意味が無いかもしれません。
最後の インタラクティブプログラミング の内容は、newLISP にも、そのまま当てはまります。
副作用を起こす関数が書けないという意味では、newLISP の方が有利かもしれません。
デザイン・ルールで気を付けなければいけないのが、“関数”ではなく“マクロ”のみで済む、という意味で。
さて、第3章 関数プログラミング のまとめです。
- newLISP でも、関数型プログラミングと命令型プログラミングの両方で書くことができます。
- newLISP では、副作用を起こす関数は定義できません。(一部例外あり)
ただし、マクロでは、副作用を起こすことが可能です。 - newLISP には、多値の戻り値はありません。
ただし、多値関数の実装は可能です。
以上、如何でしょうか?