Why Functional Programming Matters
先日の関数型言語勉強会@北海道で「なぜ関数プログラミングは重要か」を印刷したプリントを全員に配布していました。カフェとかでも気軽に読めて重宝しました。笑
うちにも一応プリンタあるんだけど、超古くて動作遅いし、ヘッドクリーニングしても謎の線(!)が沢山出てくるのでほとんど使っていない。プリンタ欲しいなぁ。。。
話が反れてしまった。
それで、勉強がてら論文中の「3.関数の貼り合わせ」に出てくる関数たち(論文中のソースはMirandaで書かれている)をCommon Lispで書いてみました。なぜLispかは聞いてはいけない。
Lispのイディオムとか関係無しに、なるべく原文に似せて書いたつもり・・・。(背景色白の方が原文(引用))
もし変なところとかあったらご指摘願います。一通り書き終わってから思ったけど、Schemeで書けば良かった。。(funcallだらけ)
+---+ sum nil = | 0 | +---+ +---+ sum (cons num list) = num | + | sum list +---+
CL-USER > (defun sum (lst) (if (null lst) 0 (+ (car lst) (sum (cdr lst))) )) SUM CL-USER > (sum '(1 2 3)) 6
sum = reduce add 0
ここに出現するreduceとCommon Lispのreduceは仕様が違うのでreduce2として定義し直した
CL-USER > (defun reduce2 (fn n) #'(lambda (lst) (reduce fn lst :from-end t :initial-value n))) REDUCE2 CL-USER > (setq sum2 (reduce2 #'+ 0)) #<anonymous interpreted function 216D1242> CL-USER > (funcall sum2 '(1 2 3)) 6
product = reduce multiply 1 anytrue = reduce or false alltrue = reduce and true
Lispのorとandはマクロなのでちょっと加工
CL-USER > (setq product (reduce2 #'* 1)) #<anonymous interpreted function 200BAC3A> CL-USER > (funcall product '(2 3 4)) 24 CL-USER > (defun or2 (a b) (or a b)) OR2 CL-USER > (defun and2 (a b) (and a b)) AND2 CL-USER > (setq anytrue (reduce2 #'or2 nil)) #<anonymous interpreted function 21753F6A> CL-USER > (funcall anytrue '(nil nil 1 nil)) 1 CL-USER > (funcall anytrue '(nil nil nil nil)) NIL CL-USER > (setq alltrue (reduce2 #'and2 t)) #<anonymous interpreted function 216C86AA> CL-USER > (funcall alltrue '(1 2 3 nil 4 5)) NIL CL-USER > (funcall alltrue '(1 2 3 4 5)) T
append a b = reduce cons b a append [1,2] [3,4] = reduce cons [3,4] [1,2] = (reduce cons [3,4]) (cons 1 (cons 2 nil)) = cons 1 (cons 2 [3,4])) (replacing cons by cons and nil by [3,4]) = [1,2,3,4]
CL-USER > (setq append2 #'(lambda (a b) (funcall (reduce2 #'cons b) a) )) #<anonymous interpreted function 200E51CA> CL-USER > (funcall append2 '(1 2 3) '(4 5 6)) (1 2 3 4 5 6)
doubleall = reduce (cons . double) nil 〜 doubleall = map double map f = reduce (cons . f) nil 〜 summatrix = sum . map sum
CL-USER > (setq doubleall (reduce2 #'(lambda (a b) (cons (* 2 a) b)) nil) ) #<anonymous interpreted function 200F91AA> CL-USER > (funcall doubleall '(1 2 3 4 5)) (2 4 6 8 10) CL-USER > (defun map2 (fn) (reduce2 #'(lambda (a b) (cons (funcall fn a) b)) nil)) MAP2 CL-USER > (setq doubleall2 (map2 #'(lambda (n) (* 2 n)))) #<anonymous interpreted function 216E6832> CL-USER > (funcall doubleall2 '(1 2 3 4 5)) (2 4 6 8 10) ;;sumは最初の方で定義した関数 CL-USER > (defun summatrix (lst) (sum (funcall (map2 #'sum) lst)) ) SUMMATRIX CL-USER > (summatrix '((1 2 3) (4 5 6) (7 8 9 10))) 55
ここからはツリー
node 1 (cons (node 2 nil) (cons (node 3 (cons (node 4 nil) nil)) nil)) redtree f g a (node label subtrees) = f label (redtree' f g a subtrees) redtree' f g a (cons subtree rest) = g (redtree f g a subtree) (redtree' f g a rest) redtree' f g a nil = a
CL-USER > ;;検証用に使うやつ (setq test-tree (cons 1 (cons (cons 2 nil) (cons (cons 3 (cons (cons 4 nil) nil)) nil)))) (1 (2) (3 (4))) CL-USER > (defun redtree2 (f g a) #'(lambda (node) (if (consp node) (funcall g (funcall (redtree f g a) (car node)) (funcall (redtree2 f g a) (cdr node)) ) a))) REDTREE2 CL-USER > (defun redtree (f g a) #'(lambda (tree) (funcall f (car tree) (funcall (redtree2 f g a) (cdr tree)) ))) REDTREE
sumtree = redtree add add 0 add 1 (add (add 2 0) (add (add 3 (add (add 4 0) 0)) 0)) = 10
CL-USER > (setq sumtree (redtree #'+ #'+ 0)) #<anonymous interpreted function 217749BA> CL-USER > (funcall sumtree test-tree) 10
labels = redtree cons append nil cons 1 (append (cons 2 nil) (append (cons 3 (append (cons 4 nil) nil)) nil)) = [1,2,3,4]
CL-USER > (setq labels (redtree #'cons append2 nil)) #<anonymous interpreted function 20094AEA> CL-USER > (funcall labels test-tree) (1 2 3 4)
maptree f = redtree (node . f) cons nil
CL-USER > (defun maptree (f) (redtree #'(lambda (a b) (cons (funcall f a) b)) #'cons nil)) MAPTREE CL-USER > (funcall (maptree #'1+) test-tree) (2 (3) (4 (5)))
これらの書き方がLispとして良いかどうかは別として(笑)何とか終わった。
4章以降は遅延評価について書かれているんですが、これはHaskellを勉強した時にでも...(逃