前回
リスト遊び 6-2 補助関数 - by shigemk2
前回のコードで、二項演算子に対応する関数を呼び出す部分は、
関数名を違うだけ引数はまったく同じ形をしている。
(defun calc (exp) (cond ((atom exp) exp) ((eq (car (cdr exp)) '+) (+ (calc (car exp)) (calc (car (cdr (cdr exp)))))) ((eq (car (cdr exp)) '-) (- (calc (car exp)) (calc (car (cdr (cdr exp)))))) ((eq (car (cdr exp)) '*) (* (calc (car exp)) (calc (car (cdr (cdr exp)))))))) calc (calc '(1 + (2 * 3))) 7
呼び出す関数を実行時に決定できればよさそうである。
二項演算子名からその計算を実行する関数名を得て、その関数を呼び出せばよろしい。
連想リストを使って、二項演算子から関数名が連想できればよい。
というわけで、前のassqを使う。
リスト遊び 4-6 連想リスト その2 - by shigemk2
funcallについてだが、funcallの第一引数が、呼び出したい関数の名前になる。
(funcall '+ 1 2) 3
;; ドット対を返す (defun assq (key alist) (cond ((null alist) nil) ;; 先頭のドット対を調べ、ドット対のCARが指すデータがkeyと同一なら、その先頭のドット対を返す ((eq key (car (car alist))) (car alist)) (t (assq key (cdr alist))))) assq ;; リストの中身を取り出す (defun op (exp) (car (cdr exp))) (defun arg1 (exp) (car exp)) (defun arg2 (exp) (car (cdr (cdr exp)))) ;; 呼び出すための演算子が格納された連想リストop-func1を作成する (setq op-func1 '((+ . +) (- . -) (* . *))) ((+ . +) (- . -) (* . *)) ;; 連想リストから演算子を取り出す関数を作成する (defun op-func (sym op-db) (cdr (assq sym op-db))) op-func (op-func '+ op-func1) + (op-func '- op-func1) - (op-func '* op-func1) * ;; funcallと、assqを利用して、本関数を短くする (defun calc (exp op-db) (cond ((atom exp) exp) (t (funcall (op-func (op exp) op-db) ;; 演算子を取り出して、関数を呼び出す (calc (arg1 exp) op-db) (calc (arg2 exp) op-db))))) calc (calc '((3 + 4) * 2) op-func1) 14 ;; 二項演算子名を自由に変更出来るという点がある。 (setq op-func2 '((add . +) (sub . -) (mul . *))) ((add . +) (sub . -) (mul . *)) ;; こういう風に書いても同じ結果が得られる (calc '((3 add 4) mul 2) op-func2) 14
リスト遊び―Emacsで学ぶLispの世界 (ASCII SOFTWARE SCIENCE Language)
- 作者: 山本和彦
- 出版社/メーカー: アスキー
- 発売日: 2000/05
- メディア: 単行本
- 購入: 2人 クリック: 76回
- この商品を含むブログ (44件) を見る