Emacs Memo
List Comprehension - defmacro によるリストの内包表記 [修正版]
Emacs Lisp版のList Comprehensionの実装についてですが、 list-of-tailの定義の中でlabelsによって定義される局所関数の第2引数 (,var)がEmacs Lispでは動的に束縛されるためにCommon Lisp版の list-of-tailと動作が異なっていますが、cl.elが定義するlexical-letを使っ て局所的な束縛に変更すればCLと同等に動作するようにならないでしょうか。
とのツッコミがしかも修正付き。どうもありがとうございます。 lexical-let か〜。うーん Lisp に興味のある人が居るのは嬉しいなぁ。
(defmacro list-of-tail (base expr &rest rest)
(cond ((null rest) `(cons ,expr ,base))
((equal (nth 1 (car rest)) 'in)
(destructuring-bind (var in generator)
(car rest)
(declare (ignore in))
(let ((f (gensym))
(z (gensym)))
`(labels ((,f (,z ,var)
(lexical-let ((,var ,var))
(list-of-tail ,z ,expr ,@(cdr rest)))))
(fold-left #',f ,base ,generator)))))
(t `(if (funcall (lambda () ,(car rest)))
(list-of-tail ,base ,expr ,@(cdr rest))
,base))))
eshell
eshell の特徴
- cd/ls/cp/mv が elisp で書かれてる.(emacs が動くとこならどこでも動く)
- コマンドの出力をバッファやキルリングやクリップボードにリダイレクトできる
- elisp でコマンドが作れる
Welcome to the Emacs shell ~ $ echo hogehoge >#<buffer *scratch*> ~ $
スクラッチバッファに echo の出力をリダイレクト(追加のときは >> を使う)
~ $ echo hogehoge >/dev/kill
キルリングに出力
~ $ echo hogehoge >/dev/clip
クリップボードに出力
List Comprehension - defmacro によるリストの内包表記
Common Lisp 用に移植した list-of マクロ が Emacs でも動くことに気がついた. destructuring-bind って elisp でも動くのか…あとはダイナミックスコープに注意すればそれなりに使えるかも.
(defun upto (a b) (if (< b a) nil (cons a (upto (1+ a) b))))
(defun fold-left (f b l)
(if (null l) b (fold-left f (funcall f b (car l)) (cdr l))))
(defmacro list-of (expr &rest rest)
`(nreverse (list-of-tail nil ,expr ,@rest)))
(defmacro list-of-tail (base expr &rest rest)
(cond ((null rest) `(cons ,expr ,base))
((equal (nth 1 (car rest)) 'in)
(destructuring-bind (var in generator)
(car rest)
(declare (ignore in))
(let ((f (gensym))
(z (gensym)))
`(labels ((,f (,z ,var) (list-of-tail ,z ,expr ,@(cdr rest))))
(fold-left #',f ,base ,generator)
))))
(t `(if (funcall (lambda () ,(car rest)))
(list-of-tail ,base ,expr ,@(cdr rest))
,base))))
ただ,upto は elisp だと再帰の深さの限界があるので,↓のように変更する.
(defun upto (from to)
(let ((acc nil))
(dotimes (i (1+ (- to from)) (nreverse acc))
(push (+ i from) acc))))
(list-of (list x y) (x in '(1 2 3)) (y in '(a b c)))
=> ((1 a) (1 b) (1 c) (2 a) (2 b) (2 c) (3 a) (3 b) (3 c))
(list-of (list x y) (x in '(1 2 3)) (y in '(1 2 3)) (= (% (+ x y) 2) 0))
=> ((1 1) (1 3) (2 2) (3 1) (3 3))