Let's start Scheme

2012-08-30

パラメタ

Schemeのparameterはわざわざ評価してやらないと値が取れないから使うのが面倒だ、と常々思っていたのだが、
識別子マクロとパラメタによる大域変数エミュレート
にそれを解消するマクロが紹介されていた。確かに、ぱっと見よさげだなぁと思ったのだが、これってSRFI-39が提供するparameterizeマクロと相性最悪じゃね?と思ってちょっと実験してみた。
(import (rnrs) (srfi :39))
(define-syntax define-identifier-parameter
  (syntax-rules ()
    ((_ var val)
     (begin
       (define t (make-parameter val))
       (define-syntax var
         (make-variable-transformer
          (lambda(x)
            (syntax-case x (set!)
              ((set! _ a) #'(t a))
              (_ #'(t))))))))))
(define-identifier-parameter *variable* 1)
(display *variable*) (newline)
(parameterize ((*variable* 2)) (display *variable*) (newline))
(display *variable*) (newline)
検証はいつもどおり、Sagittarius、YpsilonにMosh。
っで結果:
Sagittarius
Ypsilon
1を3回出力。(parameterizeされてない)
Mosh
&assertion: (1)は関数じゃないと怒られた
ふむ、パラメタはparameterizeと一緒に使われること(というか、僕は常にそれを想定)が多いと思うので、これだと、値が変更できるライブラリ変数という位置づけでしか使えないということだろうか?
面白いけど、使いどころが限定されそうだ。

2 comments:

齊藤 said...

import して set! できる変数ということだけしか意識しておらず、パラメタであることに特に意味はないつもりだった (cons でも vector でも値を入れられるものなら実装上は何でもよかった) のですが、名前に parameter と付けちゃったのでやっぱり parameter としての振舞いを期待しちゃいますね。
色々と考えてみたのですが、パラメタ関連の手続き (やマクロ) と組み合わせて使う場合は、あくまでも identifier-parameter というものであって parameter とは違うものという意識で間に変換を入れるようにするしかないんじゃないかと思います。
とりあえずこんなものを書いてみました。

http://ideone.com/epC8s

これを利用すれば以下のような要領で parameterize と組み合わせられます。

(parameterize (((identifier-parameter->parameter *variable*) 2))
(display *variable*)
(newline))

このままだと冗長ですが、好みにあわせて短い記法を用意すればそれなりに使えるんじゃないでしょうか。

kei said...

identifier-parameterであってparameterではないというのはありかもしれませんね。
set!で変更可能となると、「取り扱い注意」のラベルが必要かもしれませんが。

Post a Comment