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))