Let's start Scheme

2013-02-06

define-constant

MessagePackのR6RS Scheme用ライブラリを書いてたときにふと思いついたマクロ。
(import (for (rnrs) run expand)
        (for (rnrs eval) expand))

(define-syntax define-constant
  (lambda (x)
    (define (eval-expr k expr)
      (if (pair? (syntax->datum expr))
          (let ((r (eval (syntax->datum expr) (environment '(rnrs)))))
            (datum->syntax k r))
          expr))
    (syntax-case x ()
      ((k name expr)
       (with-syntax ((value (eval-expr #'k #'expr)))
         #'(define-syntax name
             (lambda (y)
               (syntax-case y ()
                 (var (identifier? #'var) value)))))))))

(define-constant const-1 1)
(define-constant const-2^16 (expt 2 16))

(display const-1) (newline)
(display const-2^16) (newline)
仕組みは簡単で、マクロとして束縛しつつ、define-constantマクロ展開時にexprを実行しておいてしまおうというだけのもの。込み入ったことはできないけど、(expt 2 16)とか見たいな(rnrs)の中だけで済ませられるものに対しては有効ではある。

Sagittariusには構文としてdefine-constantがあって、それで定義されたものはコンパイル時に定数として畳み込まれるんだけど、MoshやYpsilonにはない。しかも、2^16とかいいけど、もっとデカイ数字になったときにわざわざ数値リテラルで嫌だなぁと思い書いてみた。結局使ったの(expt 2 32)までだけど・・・

これと似たようなので、Vicareの中の人がよく使っている、define-inlineってのがある。こういう、コンパイラを当てにしないコードってポータブルなコードを書くときにはよく使われるのだろうか?

No comments:

Post a Comment