[Date Prev] [Date Index] [Date Next]
[Thread Prev] [Thread Index] [Thread Next]

[xyzzy:03975] Re: 行番号つきラインコピー (と質問)



やまもとさん、こんにちは。

    Wed, 26 Jan 2000 21:51:23 +0900 の
   “[xyzzy:03952] Re: 行番号つきラインコピー (と質問)”
    への返事です.

| いや〜、lispは亀井さんとか逸見さんのソースだけ見ながら
| 勉強した人間なので、ちょっと根本的に、、、

マクロは 2 回評価される関数みたいなものと思っていれば
間違いないでしょう(ただし 1 回目の評価のときには引数の
評価はされない)。ごく簡単な例をあげると、

  (defmacro foo ()
    '(+ 1 2))

このように定義して (foo) を評価すると、1 回目の評価で
(+ 1 2) が返り、それをさらに評価して 3 が返る、となり
ます。引数がある場合も同様に、

  (defmacro bar (n)
    (list '+ 1 n))

  (bar 3)
  -> (+ 1 3)
  => 4

となります。

| (M (any1) (any2) (any3)) と呼び出すと、
| 	(progn
| 	  (m-setup)
| 	  (any1)
| 	  (any2)
| 	  (any3)
| 	  (m-cleanup))
| と呼ばれるのと同じように動作してくれる物です。

この場合、引数が 3 つなので、こうなります。

  (defmacro M (a b c)
    (list 'progn '(m-setup) a b c '(m-cleanup)))

  (M (any1) (any2) (any3))
  -> (progn (m-setup) (any1) (any2) (any3) (m-cleanup))
  => ?

ふつ〜、引数は何個でもありだろうってなときは、通常の関
数と同様に &rest で受けてやればいいわけですね。

  (defmacro M2 (&rest args)
    (append '(progn) '((m-setup)) args '((m-cleanup))))

  (M2 (any1) (any2) (any3))
  -> (progn (m-setup) (any1) (any2) (any3) (m-cleanup))
  => ?

ちなみに、1 回目がどのように評価されているか(マクロの
展開)を見るには macroexpand を使います。

  (macroexpand '(M2 (any1) (any2) (any3)))
  => (progn (m-setup) (any1) (any2) (any3) (m-cleanup))


複雑なマクロ定義だと、list やら append やら cons やら 
quote やらをごちゃごちゃ書くのがめんどくせ〜、というわ
けでテンプレートを使うことができます。詳しい説明は面倒
なのでしませんが(^^; 上の例をテンプレートを使って書く
とこのようになります。

  (defmacro M (a b c)
    `(progn
       (m-setup)
       ,a ,b ,c
       (m-cleanup)))

  (defmacro M2 (&rest args)
    `(progn
       (m-setup)
       ,@args
       (m-cleanup)))

--
亀井哲弥(Tetsuya Kamei)
kamei@xxxxxxxxxxxx/JCA00343@xxxxxxxxxxx

Index Home