Upload
emasaka
View
838
Download
1
Embed Size (px)
DESCRIPTION
Citation preview
) の品格@emasaka
どう見ても出オチです
本当にありがとうございました
自己紹介● @emasaka● 本名:高橋正和● 駄洒落を検索結果にしてTwitterに流すメソッドの(たぶん)元祖● ja.wikipedia.orgで「Locator/Identifier Separation Protocol」の
ページを立てた人● 代表作:Bash on Rails● 40代 フリーター● ブログ
「本を読む」http://emasaka.blog65.fc2.com/
本題
「Lispはカッコが多い」などと申しまして
(defun fact (n) (if (zerop n) 1 (* n (fact ( n 1))) ))
階乗(factorial)をこんなふうに書いたりします
これをより厳密に書くと
(defun . (fact . ((n . nil) . ((if . ((zerop . (n . nil)) . (1 . ((* . (n . ((fact . (( . (n . (1 . nil))) . nil)) . nil))) . nil)))) . nil))))
点対表記(Dotted pair notation)
たしかにカッコが多い!
(拍手!)
命令型プログラマーならfor文か類似のループで問題を解く
(defun fact (n) (let ((i 1) (r 1)) (while (<= i n) (setq r (* r i) i (+ i 1)) ) r ))
ループで書くと
(defun . (fact . ((n . nil) . ((let . (((i . (1 . nil)) . ((r . (1 . nil)) . nil)) . ((while . ((<= . (i . (n . nil))) . ((setq . (r . ((* . (r . (i . nil))) . (i . ((+ . (i . (1 . nil))) . nil))))) . nil))) . (r . nil)))) . nil))))
これを点対表記に
これではLispに拒絶反応を示す人がいてもおかしくない
“Lisp? No!”
の恐怖
でも、Lisperなら
(3 (5 (7) 11))
このS式を見たとき
(3 . ((5 . ((7 . nil) . (11 . nil))) . nil))
これを飛ばして
こうイメージする
nil
nil
nil
3
5
7 11
木構造(ツリー)
ツリーを巡回する● 全要素を出力する● 全要素を合計する● 特定の要素を探す● …
※ブログねたの焼き直しです
方法1● car方向とcdr方向をそれぞれ再帰的に辿る● いちばんシンプルな方法
(defun traversetree (tree func) (if (atom tree) (or (null tree) (funcall func tree)) (traversetree (car tree) func) (traversetree (cdr tree) func) ))
Emacs Lispで書くと
(defun traversetree (tree func) (mapc #'(lambda (x) (if (atom x) (or (null x) (funcall func x)) (traversetree x func) )) tree ))
cdr方向をmapやループにしてもcar方向は再帰が必要
方法2● ループで辿る● 戻る場所を外部のデータ構造に覚えておく● 深さ優先ならスタック、幅優先ならキュー
実装は割愛
方法3● 再帰も外部データも使わない方法● 通ったコンスセルを破壊的に「120度回転」さ
せながら進む● 3方向(car方向、cdr方向、戻り)
= 3回120度回転 = 360度回転 = 元に戻る
図解
car cdr
こっちに進む
car
cdr
こっち(元のcar)に進みながら120度回転
戻ったら次(新しいcar)
car
cdr
戻ったら次(新しいcar)
こっち(元のcar)に進みながら120度回転
car cdr
こっち(元のcar)に進みながら120度回転
carを辿っていくだけでツリーを一巡する
,. -‐'''''""¨¨¨ヽ (.___,,,... -ァァフ| あ…ありのまま 今 起こった事を話すぜ! |i i| }! }} //| |l、{ j} /,,ィ//| 『おれはcarを辿っていたと i|:!ヾ、_ノ/ u {:}//ヘ 思ったらいつのまにかツリーを一周していた』 |リ u' } ,ノ _,!V,ハ | /´fト、_{ル{,ィ'eラ , タ人 な… 何を言ってるのか わからねーと思うが /' ヾ|宀| {´,)⌒`/ |<ヽトiゝ おれも何をされたのかわからなかった… ,゙ / )ヽ iLレ u' | | ヾlトハ〉 |/_/ ハ !ニ⊇ '/:} V:::::ヽ 頭がどうにかなりそうだった… // 二二二7'T'' /u' __ /:::::::/`ヽ /'´r -—一ァ‐゙T´ '"´ /::::/-‐ \ 再帰だとかスタックだとか / // 广¨´ /' /:::::/´ ̄`ヽ ⌒ヽ そんなチャチなもんじゃあ 断じてねえ ノ ' / ノ:::::`ー-、___/:::::// ヽ }_/`丶 /:::::::::::::::::::::::::: ̄`ー-{:::... イ もっと恐ろしいものの片鱗を味わったぜ…
(defun traversetree:spin (cns prev) (let ((next (car cns))) (rplaca cns (cdr cns)) (rplacd cns prev) next ))
(defun traversetree (tree func) (let* ((marker "dummy") ; unique object (cns tree) (prev marker) next ) (while (not (eq (setq next (traversetree:spin cns prev) ) marker )) (if (consp next) (setq prev cns cns next) (or (null next) (funcall func next)) (setq prev next) ))))
Emacs Lispで書くと
● 元ネタは、20年ぐらい前に雑誌(bit?)のエッセイかなにかでアイデアを見た記憶● 詳細はぜんぜん覚えてない● ご存知の方、教えてください
● 実践的ではない● いくら関数型じゃなくても、無駄な破壊的操作はい
まどき流行らない?
DEMO
まとめ
● カッコは単なる格好● ツリーですた●【緩募】元ネタの情報