[1]> (defmacro inc! (var)`(setq var (1+ var))) INC! [2]> (let ((x 1))(macroexpand '(inc! x))) (SETQ VAR (1+ VAR)) ; T [3]> (defmacro inc! (var)`(setq ,var (1+ ,var))) INC! [4]> (let ((x 1))(macroexpand '(inc! x))) (SETQ X (1+ X)) ; T [5]>On LispもLOLもせっかくWebで読めるので参考にしてはどうでしょう。 こんなとこでドヤ顔しながら回答しても無意味だけど。
2011/12/22
Re: lispのマクロ定義について
最初の例は動かないんじゃないかなー。取りあえずmacroexpandしたらいいかと。この辺はLOLの評価の梯子(だっけ?)の話がわかりやすかった。
labels :
common lisp,
defmacro
2011/11/05
ておくlet
defmacro
syntax-rules
(define-macro (teoku-let binds . body) `(let ,(map (lambda (ls) (cons (car ls)'("ておくれ"))) binds) ,@body)) (teoku-let ((wasao 68) (gentoo 'linux) (kumamoto "熊本")) (print wasao) (print gentoo) (print kumamoto)) ;; ておくれ ;; ておくれ ;; ておくれ
syntax-rules
(define-syntax teoku-let (syntax-rules () ((_ () body ...) (let () body ...)) ((_ ((var val) x ...) body ...) (let ((var "ておくれ")) (teoku-let (x ...) body ...))))) (teoku-let ((wasao 68) (gentoo 'linux) (kumamoto "熊本")) (print wasao) (print gentoo) (print kumamoto)) ;; ておくれ ;; ておくれ ;; ておくれ
labels :
defmacro,
Gauche,
scheme,
syntax-rules
2011/06/05
Gaucheのmoduleとdefine-in-moduleとevalで作るsandbox
まずはモジュールがどういうものか、いくつか確認してみます。
ということで、nullモジュール内にすでにある束縛を見てみる。
select-moduleでnullモジュールに入ってみます。
他にも追加してみる。
+と、きっとprintもないのでnullモジュールに注入します。
sandboxを作ってみる。
これはsandboxとしてはまずそうです。sandboxモジュールはnullモジュールから直接継承してもらいたいので、継承関係をぶち壊すためにextendマクロを使います。
ホントに?
書いてみます。
期待通りに展開されるか%macroexpandマクロで確認してみます。
動作も期待通りでしょうか?
ですが・・・、sandbox内で使いたい手続きやマクロを全てdefine-in-moduleで定義していくのも結構しんどそうです。define-sandboxで下記のように書けたら嬉しいかもしれません。
展開イメージはこんな感じ。
define-sandboxマクロを編集します。
動作を確認してみます。
でも、sandbox内で使いたい手続きやマクロを毎度一つずつ追加するのも面倒です。指定したモジュールだけsandbox内でuseできたら便利そうです。
展開イメージはこうでしょうか。
define-sandboxを拡張します。
%macroexpandしてみます。
期待通りの動きをするでしょうか。
取りあえずこれでdefine-sandboxは完成ということにします。
あとは、define-sandboxでsandboxを定義した後に束縛を追加したくなったりuseされるモジュールを追加したくなった場合のために、inject-sandbox-symbols, inject-sandbox-modulesのようなマクロがあると便利かもしれません。
これでネットワーク越しに受け取ったS式などを心置きなくevalできますね!
モジュールは、シンボルを束縛へとマップするオブジェクト
モジュールは継承することもできます。 既存のモジュールを継承したモジュールに新しい束縛を足してexportすることにより、 既存のモジュールを拡張することができます。新しいモジュールの内部からは、 継承元のモジュールの束縛が(exportされていないものも含め)全て見えます。 (新しく作られるモジュールはデフォルトでgaucheモジュールを継承しています。 新しいモジュールからgaucheの組込み手続き等が使えるのはそのためです)。
モジュールは実行時データ構造です。実行時に任意の名前のモジュールを 手続き的に作成することができます。
define-moduleはモジュールに名前を付けるが、 Gaucheでは無名のモジュールを作ることもできる。
module
select-moduleによって一度nullやschemeモジュールに 入ると、そこから他のモジュールに移ることはできなくなることに注意してください。 これらのモジュールからは、あらゆるモジュール操作構文が不可視だからです。らしい。
ということで、nullモジュール内にすでにある束縛を見てみる。
(hash-table-keys (module-table (find-module 'null))) ;; -> (unquote-splicing quasiquote letrec-syntax syntax-rules set! lambda let* begin quote or unquote define case delay if let letrec and let-syntax cond do define-syntax)確かにモジュール系の手続きや特殊形式が一式存在しない。ということはselect-moduleをnullモジュールに入れてあげれば、またuserモジュールなどに戻れるわけですね。
define-in-module
nullモジュールにselect-module特殊形式を入れてみる。(define-in-module null select-module select-module) (hash-table-keys (module-table (find-module 'null))) ;; -> (unquote-splicing quasiquote letrec-syntax syntax-rules set! lambda let* begin quote or unquote define case delay if select-module let letrec and let-syntax cond do define-syntax)入ったようです。
select-moduleでnullモジュールに入ってみます。
(select-module null) (module-name (current-module)) ;; -> *** ERROR: unbound variable: current-module (select-module user) (module-name (current-module)) ;; -> usernullモジュール内にcurrent-moduleは無いのでエラーになってます。でもselect-moduleはあるのでuserモジュールに戻ってくることができました。
他にも追加してみる。
(define-in-module null current-module current-module) (define-in-module null receive receive) (define-in-module null values values) (select-module null) (current-module) ;; -> #<module null> (receive (a b) (values 1 2) (quasiquote ((unquote a)(unquote b)))) ;; -> (1 2)
eval
ところで、gaucheのevalの第二引数は(今のところ)モジュールらしいです。Function: eval expr env
[R5RS] exprを評価します。envは下に述べる手続きにより 返される値でなければなりません。現時点では、それは単なるオブジェクトですが、Gaucheが将来、ファースト クラスの環境オブジェクトを採用する可能性はあります。
(eval '(print #`"Hello, ,(module-name (current-module)) module !!") (current-module)) ;; Hello, user module !! ;; #<undef> (eval '(print #`"Hello, ,(module-name (current-module)) module !!") (find-module 'gauche)) ;; Hello, gauche module !! ;; #<undef>
sandbox
サンドボックス(sandbox)とは、外部から受け取ったプログラムを保護された領域で動作させることによってシステムが不正に操作されるのを防ぐセキュリティモデルのこと。nullモジュールを継承したモジュールを作れば、許可したい手続きだけを注入したsandboxが作れそうです。
(eval '(begin (define a 10)(define b 5)(print (+ a b))) (find-module 'null)) ;; -> *** ERROR: unbound variable: ++がないと怒られました。
+と、きっとprintもないのでnullモジュールに注入します。
(define-in-module null + +) (define-in-module null print print) (eval '(begin (define a 10)(define b 5)(print (+ a b))) (find-module 'null)) ;; 15 ;; #<undef>
sandboxを作ってみる。
(define-module sandbox) (module-parents (find-module 'sandbox)) ;; -> (#<module gauche.gf>)まずdefine-moduleでsandboxモジュールを定義します。sandboxモジュールの親モジュールはgauche.gfモジュールになっているようです。ということは、userモジュールと同じだけの手続きやマクロが使えてしまいそうです。昨日書いてみたall-symbols手続きを少し改造して確認してみます。
(define (all-parents module) (let ((parents (module-parents module))) (let rec ((parents parents)(acc '())) (if (null? parents) acc (rec (cdr parents)(append (cons (car parents) acc) (all-parents (car parents)))))))) (define (all-symbols module) (map (lambda (m) (sort (hash-table-keys (module-table m)) (lambda (x y) (string<? (symbol->string x) (symbol->string y))))) (all-parents module))) (length (apply append (all-symbols (find-module 'sandbox)))) ;; -> 14231423個もありました。
これはsandboxとしてはまずそうです。sandboxモジュールはnullモジュールから直接継承してもらいたいので、継承関係をぶち壊すためにextendマクロを使います。
(eval '(extend null) (find-module 'sandbox)) (module-parents (find-module 'sandbox)) ;; -> (#<module null>)希望通りにsandboxモジュールはnullモジュールを直接継承したようです。
ホントに?
(module-parents (find-module 'sandbox)) ;; -> (#<module null>) (hash-table-keys (module-table (find-module 'sandbox))) ;; -> () (length (apply append (all-symbols (find-module 'sandbox)))) ;; -> 22 (apply append (all-symbols (find-module 'sandbox))) ;; -> (and begin case cond define define-syntax delay do if lambda let let* let-syntax letrec letrec-syntax or quasiquote quote set! syntax-rules unquote unquote-splicing) (module-parents (find-module 'sandbox)) ;; -> (#<module null>)よさそうです。
define-sandbox
こういう風に書きたいですよね。(define-sandbox <name>)これが下記のように展開されるマクロがあれば良さそうです。
(begin (define-module <name>) (define <name> (find-module (quote <name>))) (eval '(extend null) <name>))
書いてみます。
(define-macro (define-sandbox name) `(begin (define-module ,name) (define ,name (find-module (quote ,name))) (eval '(extend null) ,name)))
期待通りに展開されるか%macroexpandマクロで確認してみます。
(%macroexpand (define-sandbox hoge)) ;; (begin ;; (define-module hoge) ;; (define hoge (find-module 'hoge)) ;; (eval '(extend null) hoge))
動作も期待通りでしょうか?
(define-sandbox hoge) hoge ;; -> #<module hoge> (module-parents hoge) ;; -> (#<module null>) (apply append (all-symbols hoge)) ;; -> (and begin case cond define define-syntax delay do if lambda let let* let-syntax letrec letrec-syntax or quasiquote quote set! syntax-rules unquote unquote-splicing)良さそうです。
ですが・・・、sandbox内で使いたい手続きやマクロを全てdefine-in-moduleで定義していくのも結構しんどそうです。define-sandboxで下記のように書けたら嬉しいかもしれません。
(define-sandbox <name> (symbol ... ))
展開イメージはこんな感じ。
(begin (define-module <name>) (define <name> (find-module (quote <name>))) (eval '(extend null) <name>) (begin (define-in-module <name> symbol symbol) ... ))
define-sandboxマクロを編集します。
(define-macro (define-sandbox name . symbols) `(begin (define-module ,name) (define ,name (find-module (quote ,name))) (eval '(extend null) ,name) (begin ,@(map (lambda (sym) `(define-in-module ,name ,sym ,sym)) symbols) (undefined))))
動作を確認してみます。
(%macroexpand (define-sandbox hoge)) ;; (begin ;; (define-module hoge) ;; (define hoge (find-module 'hoge)) ;; (eval '(extend null) hoge) (begin)) (%macroexpand (define-sandbox fuga + * - /)) ;; (begin ;; (define-module fuga) ;; (define fuga (find-module 'fuga)) ;; (eval '(extend null) fuga) ;; (begin ;; (define-in-module fuga + +) ;; (define-in-module fuga * *) ;; (define-in-module fuga - -) ;; (define-in-module fuga / /))) (define-sandbox fuga + * - /) (hash-table-keys (module-table fuga)) ;; -> (/ * - +) (module-parents fuga) ;; -> (#<module null>)良さそうですね。
でも、sandbox内で使いたい手続きやマクロを毎度一つずつ追加するのも面倒です。指定したモジュールだけsandbox内でuseできたら便利そうです。
(define-sandbox <name> (using-module ...) (symbol ...))
展開イメージはこうでしょうか。
(begin (define-module <name>) (define <name> (find-module (quote <name>))) (eval '(begin (use using-module) ...) <name>) (eval '(extend null) <name>) (begin (define-in-module <name> symbol symbol) ... ))
define-sandboxを拡張します。
(define-macro (define-sandbox name modules . symbols) `(begin (define-module ,name) (define ,name (find-module (quote ,name))) (eval (quote (begin ,@(map (lambda (m) `(use ,m)) modules))) ,name) (eval '(extend null) ,name) (begin ,@(map (lambda (sym) `(define-in-module ,name ,sym ,sym)) symbols) (undefined))))
%macroexpandしてみます。
(%macroexpand (define-sandbox hoge (srfi-1 util.list gauche.sequence) + - * /)) ;; (begin ;; (define-module hoge) ;; (define hoge (find-module 'hoge)) ;; (eval '(begin (use srfi-1) (use util.list) (use gauche.sequence)) hoge) ;; (eval '(extend null) hoge) ;; (begin ;; (define-in-module hoge + +) ;; (define-in-module hoge - -) ;; (define-in-module hoge * *) ;; (define-in-module hoge / /) ;; (undefined)))
期待通りの動きをするでしょうか。
(define-sandbox hoge (srfi-1 util.list gauche.sequence) + - * /) (module-parents hoge) ;; -> (#<module null>) (hash-table-keys (module-table hoge)) ;; -> (/ * - +) (eval 'iota hoge) ;; -> #<closure iota> (eval 'assoc-ref hoge) ;; -> #<closure assoc-ref> (eval 'fold-with-index hoge) ;; -> #<generic fold-with-index (3)> (eval 'list hoge) ;; -> *** ERROR: unbound variable: list (eval 'map hoge) ;; -> #<generic map (2)>define-sandbox時に指定したモジュールからexportされている束縛はsandbox内から見えているようです。define-in-moduleで指定されていない束縛であるlistは見えていません。これで良さそうです。
取りあえずこれでdefine-sandboxは完成ということにします。
(define-macro (define-sandbox name modules . symbols) `(begin (define-module ,name) (define ,name (find-module (quote ,name))) (eval (quote (begin ,@(map (lambda (m) `(use ,m)) modules))) ,name) (eval '(extend null) ,name) (begin ,@(map (lambda (sym) `(define-in-module ,name ,sym ,sym)) symbols) (undefined))))
あとは、define-sandboxでsandboxを定義した後に束縛を追加したくなったりuseされるモジュールを追加したくなった場合のために、inject-sandbox-symbols, inject-sandbox-modulesのようなマクロがあると便利かもしれません。
これでネットワーク越しに受け取ったS式などを心置きなくevalできますね!
参考
@kikuchan98さんに教えてもらった内容を参考にしました。追記
探してみたらkahuaにsandbox.scmというものがあった。どうやら上記のsandboxとは違ってブラックリストを指定するタイプみたい。それとmake-moduleを使って無名モジュールを作ってそれをsandboxにしているみたい。追記
- vallog: なんで Lisp/Scheme の変数名は長いの?
- vallog: Gauche: use してる module から export されてる symbol たち
- vallog: 初期状態で見えているsymbolたち(Gaucheのuserモジュール)
2011/02/12
プログラミング Gauche の object マクロと LOL の dlambda マクロ
プログラミング Gauche をパラパラ読んでたら、P.270 に object というマクロ(syntax-rules)が載ってたんですね。よく見たら、どこかで見たこのあるような形と機能だなーと。LOL(LET OVER LAMBDA Edition 1.0)の dlambda にそっくりなんですね。
dlambda はもともと Common Lisp の伝統的なマクロで書かれているので、見た目は object マクロとは似ていません。ですが、dlambda を scheme の衛生的マクロで書くとそっくりです。(似たような機能なのでそりゃそうなんですが)
以前書いた衛生的マクロ版 dlambda をちょっと書き直して再掲するとこんなの。
使い方はこんな感じ。
で、これが プログラミング Gauche に載ってる object マクロ。(P.270)
で、こんな感じでオブジェクトっぽいものを作るのに使える。
メソッド名はキーワードでも良いかも。こんな風に。
プログラミング Gauche を読んでたら object マクロが目にとまりました -> LOL の dlambda に似てるなー -> ただそれだけです。
ついでに LOL に載ってる Common Lisp 版の dlambda 。
LOL の dlambda には defmacro! が必要なので、実際に使うには以下のようになる。伝統的マクロは確かに強力だけど、syntax-rules だと簡単に書けるものもあるので、syntax-rules も結構よくね?
dlambda はもともと Common Lisp の伝統的なマクロで書かれているので、見た目は object マクロとは似ていません。ですが、dlambda を scheme の衛生的マクロで書くとそっくりです。(似たような機能なのでそりゃそうなんですが)
以前書いた衛生的マクロ版 dlambda をちょっと書き直して再掲するとこんなの。
(define-syntax dlambda (syntax-rules (else) ((_ (msg (arg ...) body ...) ...) (^ (key . args) (case key ((msg)(apply (^ (arg ...) body ...) args)) ... (else key)) ))))
使い方はこんな感じ。
(define counter (let1 count 0 (dlambda (inc (:optional (n 1))(inc! count n)) (dec (:optional (n 1))(dec! count n))))) (counter 'inc) ;; -> 1 (counter 'inc) ;; -> 2 (counter 'dec 10) ;; -> -6
で、これが プログラミング Gauche に載ってる object マクロ。(P.270)
(define-syntax object (syntax-rules () [(object (ivar ...) (method (arg ...) body ...) ...) (lambda (ivar ...) (lambda (message . args) (case message [(method) (apply (lambda (arg ...) body ...) args)] ...)))] ))
で、こんな感じでオブジェクトっぽいものを作るのに使える。
(define make-count (let1 count 0 (object () (inc (:optional (n 1))(inc! count n)) (dec (:optional (n 1))(dec! count n))))) (define counter (make-count)) (counter 'inc) ;; -> 1 (counter 'inc 10) ;; -> 11 (counter 'dec) ;; -> 10
メソッド名はキーワードでも良いかも。こんな風に。
(define make-count (let1 count 0 (object (:optional step) (:inc (:optional (n step))(inc! count n)) (:dec (:optional (n step))(dec! count n))))) (define counter (make-count 3)) (counter :inc) ;; -> 3 (counter :inc 1) ;; -> 4object マクロの方が初期値を取れる分良いかも。
プログラミング Gauche を読んでたら object マクロが目にとまりました -> LOL の dlambda に似てるなー -> ただそれだけです。
ついでに LOL に載ってる Common Lisp 版の dlambda 。
(defmacro! dlambda (&rest ds) `(lambda (&rest ,g!args) (case (car ,g!args) ,@(mapcar (lambda (d) `(,(if (eq t (car d)) t (list (car d))) (apply (lambda ,@(cdr d)) ,(if (eq t (car d)) g!args `(cdr ,g!args))))) ds))))
LOL の dlambda には defmacro! が必要なので、実際に使うには以下のようになる。伝統的マクロは確かに強力だけど、syntax-rules だと簡単に書けるものもあるので、syntax-rules も結構よくね?
(defun flatten (x) (labels ((rec (x acc) (cond ((null x) acc) ((atom x) (cons x acc)) (t (rec (car x) (rec (cdr x) acc)))))) (rec x nil))) (defun mkstr (&rest args) (with-output-to-string (s) (dolist (a args) (princ a s)))) (defun symb (&rest args) (values (intern (apply #'mkstr args)))) (defun g!-symbol-p (s) (and (symbolp s) (> (length (symbol-name s)) 2) (string= (symbol-name s) "G!" :start1 0 :end1 2))) (defmacro defmacro/g! (name args &rest body) (let ((syms (remove-duplicates (remove-if-not #'g!-symbol-p (flatten body))))) `(defmacro ,name ,args (let ,(mapcar (lambda (s) `(,s (gensym ,(subseq (symbol-name s) 2)))) syms) ,@body)))) (defun o!-symbol-p (s) (and (symbolp s) (> (length (symbol-name s)) 2) (string= (symbol-name s) "O!" :start1 0 :end1 2))) (defun o!-symbol-to-g!-symbol (s) (symb "G!" (subseq (symbol-name s) 2))) (defmacro defmacro! (name args &rest body) (let* ((os (remove-if-not #'o!-symbol-p args)) (gs (mapcar #'o!-symbol-to-g!-symbol os))) `(defmacro/g! ,name ,args `(let ,(mapcar #'list (list ,@gs) (list ,@os)) ,(progn ,@body))))) (defmacro! dlambda (&rest ds) `(lambda (&rest ,g!args) (case (car ,g!args) ,@(mapcar (lambda (d) `(,(if (eq t (car d)) t (list (car d))) (apply (lambda ,@(cdr d)) ,(if (eq t (car d)) g!args `(cdr ,g!args))))) ds))))
labels :
defmacro,
scheme,
syntax-rules
2010/09/23
番号付き部分適用 cutn
先日書いた defmacro! がバグっていたので
先日書いたものがバグっていたので、修正しようとしましたが解決できず・・・。
バグは、defmacro! で可変長引数が取れないというものです。
例えば、
(defmacro! (sum . args) ...
とした時に args を filter して o! シンボルを g! シンボルに置き換えようとするところで、args がまだシンボルのままであるためエラーになるというものです。よって、その処理を書く場所に気をつけて評価順序を制御すれば良いだろうと思って修正を試みていたのですが、なかなかうまくいかず。。悔しいれす(^p^)
猫好きながら猫アレルギーにより鼻水ダラダラを理由に今日は一旦諦めます。。
バグは、defmacro! で可変長引数が取れないというものです。
例えば、
(defmacro! (sum . args) ...
とした時に args を filter して o! シンボルを g! シンボルに置き換えようとするところで、args がまだシンボルのままであるためエラーになるというものです。よって、その処理を書く場所に気をつけて評価順序を制御すれば良いだろうと思って修正を試みていたのですが、なかなかうまくいかず。。悔しいれす(^p^)
猫好きながら猫アレルギーにより鼻水ダラダラを理由に今日は一旦諦めます。。
追記
勘違いだったようです。というか見当違いでした。filter の引数に非リストを渡していたからっぽい。全然見当違いの修正を数時間やってました。。ご飯食べてお風呂入って、再度コードを見たらあっけなく・・・。2010/09/15
LOL defmacro!
LET OVER LAMBDA Edition 1.0 の defmacro! を scheme(Gauche)で書きました。
基本的に同じものですが、実験的に g! や o! を変更できるようにしています。
Un-Common Lisp の defmacro* がプレフィックスに g!, o! をつけるのでなく、サフィックスに #, % を付けるスタイルなのを見て、切り替えられるようにしてみても良いかなぁと。切り替え方が不細工ですが、まぁお試しということで。
使用例はこんな感じ。
以下 defmacro! のコード。
基本的に同じものですが、実験的に g! や o! を変更できるようにしています。
Un-Common Lisp の defmacro* がプレフィックスに g!, o! をつけるのでなく、サフィックスに #, % を付けるスタイルなのを見て、切り替えられるようにしてみても良いかなぁと。切り替え方が不細工ですが、まぁお試しということで。
使用例はこんな感じ。
以下 defmacro! のコード。
追記
defmacro! に可変長引数が受け取れないバグがありました。修正しました。2010/09/09
syntax-rules, defmacro: define-cxr, define-cxr*
caaaar とか cadadadar などを定義するマクロ。LET OVER LAMBDA Edition 1.0 にもありました。
取りあえず書いてみました。
組み合わせて作っていく感じ。car + car で caar を作る、みたいな。
以下コード。
自分なりに考えてみたもの。もといし、効率も悪いけど意図通り動きます。
こちらは (define-cxr caar) とされたら a と d を car と cdr として手続きを組み立てる感じ。でも入力を制限していないので、my-caaar が caaar 相当の手続きに、ashitahadounaru? が caaadar 相当の手続きになります。。
追記
下のコード貼り間違えてました。修正。
取りあえず書いてみました。
組み合わせて作っていく感じ。car + car で caar を作る、みたいな。
以下コード。
自分なりに考えてみたもの。もといし、効率も悪いけど意図通り動きます。
こちらは (define-cxr caar) とされたら a と d を car と cdr として手続きを組み立てる感じ。でも入力を制限していないので、my-caaar が caaar 相当の手続きに、ashitahadounaru? が caaadar 相当の手続きになります。。
追記
下のコード貼り間違えてました。修正。追記2
map-accum でなくてもよかったですね。fold-right でよさそうです。(define (cxr->ad-fun-lis sym)
(fold-right (lambda (e acc)
(let1 p (coalesce ((eq? e 'a) car)
((eq? e 'd) cdr))
(if p
(cons p acc)
acc))) '() (symbol->list sym)))
labels :
defmacro,
Gauche,
LOL,
scheme,
syntax-rules
2010/08/26
syntax-rules: cut っぽい let
たまたま、試しにこういうアナフォリックマクロを書いていました。値を一時的に束縛したいけど、名前を付けたいわけではないことがよくある気がしたので。別に <> じゃなくて On Lisp の aif や aand みたいに it でも良いんですけども。
そこで、srfi-26 の cut っぽい let があったら便利そうだなぁ。。と思ったので、こちらも試しに書いてみました。みましたが・・・。(名前は、cut っぽい let -> cutlet -> cet と取りあえず)
ネストした時ダメですね。。こういう時はどう扱ったら良いんでしょうか。わかりません。以下のように少し書き足してもみましたが・・・。動いたとしても、ここまでするなら一番最初のアナフォリックマクロで良いかなーと思いました。
しかし、srfi のコードは美しいですねぇ。今回も大変勉強になりました。
そこで、srfi-26 の cut っぽい let があったら便利そうだなぁ。。と思ったので、こちらも試しに書いてみました。みましたが・・・。(名前は、cut っぽい let -> cutlet -> cet と取りあえず)
ネストした時ダメですね。。こういう時はどう扱ったら良いんでしょうか。わかりません。以下のように少し書き足してもみましたが・・・。動いたとしても、ここまでするなら一番最初のアナフォリックマクロで良いかなーと思いました。
しかし、srfi のコードは美しいですねぇ。今回も大変勉強になりました。
追記
コメント欄が面白かったので。
labels :
defmacro,
Gauche,
scheme,
srfi,
syntax-rules
2010/08/05
PAIP 2.2 でちょっとしたマクロ
PAIP(実用 Common Lisp (IT Architects’Archive CLASSIC MODER))の当該箇所の本題とは無関係なのですが、マクロを書いたので晒しておきます。
以下コード。一番上が書籍に載っているもの。2, 3番目がマクロ。
私は On Lisp も LET OVER LAMBDA Edition 1.0 も読んだわけですが、"読んだ"だけで書けるようになったわけではありません。どうやら。書かないと書けるようにはならないでしょうね。両書籍も書きながら再読しないといけませんね。
ちなみに書籍は Common Lisp ですが、今のところ Scheme(Gauche)で書いています。
この分厚い書籍を携帯したり、電車の中で読むには勇気が要りますね。。今日から実行していますが。。
以下コード。一番上が書籍に載っているもの。2, 3番目がマクロ。
私は On Lisp も LET OVER LAMBDA Edition 1.0 も読んだわけですが、"読んだ"だけで書けるようになったわけではありません。どうやら。書かないと書けるようにはならないでしょうね。両書籍も書きながら再読しないといけませんね。
ちなみに書籍は Common Lisp ですが、今のところ Scheme(Gauche)で書いています。
この分厚い書籍を携帯したり、電車の中で読むには勇気が要りますね。。今日から実行していますが。。
labels :
defmacro,
Gauche,
PAIP,
scheme,
syntax-rules
2010/06/06
anaphora
2010/05/18
On Lisp からいくつか
読んでいて「おっ」と思ったところを、メモっておいても良いですか?
関数定義内にあるマクロ呼び出しは関数がコンパイルされるときに展開形に置換される. マクロを呼び出す関数がコンパイルされた後にそのマクロを再定義したらどうなるだろうか? 元々のマクロ呼び出しの形跡は残っていないので,関数内の展開形は更新されない.
applyやfuncallの第1引数としては渡せないし, 呼出側の関数が新たなローカルな束縛を生むような環境では使うべきでない.
マクロ呼び出しは,書かれた所に直接展開される.
マクロはマクロ呼び出し内の引数の評価を制御する. 評価回数は引数がマクロの展開コードのどこに置かれるかによるが, 1回でも複数回でも良いし,全く評価しないこともある.
Lispプログラムでのマクロ展開は全てプログラムがコンパイルされたときに行われ, コンパイル時に実行できるどのような計算も,実行時にプログラムを遅くすることはない.
関数は(例えばapplyに)引数として渡すことも,関数から返すことも, データ構造内に格納することもできる. マクロではそれらはどれも不可能だ. これらはマクロ呼び出しをλ式で包むことで実現できる場合がある.
言われてみれば、そりゃそうだ、というものが多い気もしますが、なるほどです。
LET OVER LAMBDA Edition 1.0 もおもしろいけど、On Lisp はもっとおもしろい。LET OVER LAMBDA Edition 1.0 の著者が以下のように言うのもわかる気がする。
マクロに興味を持つ者なら誰もが、On Lisp の一言一句を逃さず読まなければならない。
こんなに引用ばかりで良いのかな。でもメモっておきたかったので。
2010/05/15
defmacro while
do マクロの使い方を覚えられないクラスタです。
再帰で書いてみましたが、do マクロ版と同等かよくわかりません。
上が、On Lisp に載ってる版。下が再帰版。
最基盤再帰版は戻り値が常に nil ですね(笑)
再帰で書いてみましたが、do マクロ版と同等かよくわかりません。
上が、On Lisp に載ってる版。下が再帰版。
追記
追記2
格好悪いですが、これなら?追記3
nil で良かった件。追記4
prog1 の方もちゃんと戻ってないですね(笑)追記5
@valvallow 暗黙の block と tagbody が無いので、return や return-from や go が使えない点がホンモノと違うかも?less than a minute ago via TweenSeaoak
seaoak2003
追記6
labels :
common lisp,
defmacro
2010/05/10
『Schemeのマクロは変数衝突を「自動的に回避する」』
Schemeのマクロは変数衝突を「自動的に回避する」と書きましたが、一体どうやって 回避してるんでしょうか。
ローカル束縛(arithmetic-ifにおける変数var)の衝突の回避については、 マクロ展開ルーチンがマクロが挿入する変数varを衝突しないようにリネーム してやることで回避できます。gensymをマクロシステムが自動的にやってくれると 言っても良いでしょう。
- Island Life - Schemeのマクロ
- LOLのdefmacro!gをGaucheで - みずぴー日記
- defmacro - 主題のない日記
- How To Become A Hacker: alambda
- How To Become A Hacker: dlambda
これは・・・
- Let Over Lambda / Schemer 5.7 - 月の塵
- Let Over Lambda / Schemer: 4 - 月の塵
- Let Over Lambda / Schemer: 5.1 - 月の塵
- create syntax-rules with defmacro - 月の塵
あと、これも。togetter を貼りつけてみたいというのもあったので。
勝手にトゥギャりました。誰でも編集できるにしているので、自由に編集してください。
labels :
defmacro,
Gauche,
LOL,
scheme,
syntax-rules
2010/04/13
LOL tree-leaves
2010/04/06
defmacro: LOL nif
defmacro: LOL nlet
2010/03/29
登録:
投稿 (Atom)