Code Aquarium

minazoko's blog -*- 水底のブログ -*-

ifマクロ

Gaucheでifマクロを書いてみた。

マクロ名は if だとアレなので %if とする。
当然ながら if case cond といった分岐用特殊形式の使用は禁止。
else無指定への対応すると煩雑になるので2つに分けています。

(define-macro (%__if test then else)
  `((assoc-ref 
     `((#t . ,(^() ,then))
       (#f . ,(^() ,else)))
     (boolean ,test))))

(define-macro (%if test then . else)
  `($ %__if ,test
      ,then
      ,($ %__if (null? else)
          (undefined)
          (car else))))

thenとelseの式をサンクにするので名前付letの再帰は上手くいかないかな、と思いましたが大丈夫でした。

(let loop ((n 10) (acc 1))
  (%if (zero? n)
       acc
     (loop (- n 1) (* acc n))))  ;; ループ呼び出しがサンクになってる。
;;=> 3628800

ちなみにClojureで同様にしてrecurをサンクにすると上手くいきませんでした。recurのジャンプ先がloopではなくサンクを作っている fn になってしまうからですね。