4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

datum->syntaxの嵌りどころと駄文

Last updated at Posted at 2015-01-25

#datum->syntaxの嵌りどころ

R6RSにはdatum->syntaxという手続きがある。これを使えばaif等のsyntax-rulesのみでは書くことが難しいマクロ1も書くことができる。例えばaifは以下のように書ける。

aif.scm
#!r6rs
(import (rnrs))

(define-syntax aif
  (lambda (x)
    (syntax-case x ()
      ((aif test then)
       #'(aif test then #f))
      ((aif test then else)
       (with-syntax ((it (datum->syntax #'aif 'it)))
         #'(let ((it test))
             (if it then else)))))))

(aif (assq 'a '((a . 0) (b . 1))) it #f)
;; -> (a . 0)

ここまでならば嵌りどころはないように思えるが、上記の定義を以下のようにすると問題が起きる。

aif-broken.scm
#!r6rs
(import (rnrs))

(define-syntax aif
  (lambda (x)
    (syntax-case x ()
      ((_ test then) ;; here is got changed
       #'(aif test then #f))
      ((aif test then else)
       (with-syntax ((it (datum->syntax #'aif 'it)))
         #'(let ((it test))
             (if it then else)))))))

(aif (assq 'a '((a . 0) (b . 1))) it) ;; use the first pattern
;; error unbound variable it

これはdatum->syntaxでテンプレートとして受け取る識別子が最初のパターンで生成されたテンプレート変数になるため、本来の構文情報を取得できないからである。これを回避するためには最初に示したように_を使わずに何かしらのパターン変数で置換してやる必要がある。

この嵌りどころはsyntax-caseのみを使っているのであれば問題はないのだが、syntax-rulesと組み合わせると意外なところで嵌ることがある。例えば以下のようなコードを考えてみる。

wrapped-aif.scm
#!r6rs
(import (rnrs))

(define-syntax aif
  (lambda (x)
    (syntax-case x ()
      ((k test then else)
       (with-syntax ((it (datum->syntax #'k 'it)))
         #'(let ((it test))
             (if it then else)))))))

(define-syntax wrapped-aif
  (syntax-rules ()
    ((_ test then else)
     (aif test then else))))

(wrapped-aif (assq 'a '((a . 0) (b . 1))) it #f)
;; -> error unbound variable it

一見特に問題がないように見えるのだが_it_はaifの構文情報で生成されるのでwrapped-aifからは参照することができない。解決方法は読者への宿題とすることにする23

#駄文

ここからは駄文である。関数型ポエムを大量に書いていた人の処分についてであり、特に読む必要はないので、適当に読み飛ばしていただきたい。

全てを観測したわけでもないので事実と反する部分があるかもしれないが、結果としてポエムを大量生成していたかの氏はアカウント凍結という処分になったようである。この決定について一点だけ懸念がある。氏のアカウント凍結は、他者への誹謗、中傷を行ったためという理由であってほしいということだ。多くの人が技術的に間違いであり、指摘してもそれが直ることがないということを気にしていたようであるが、それが理由での凍結であれば、Qiitaというサービスは学者もしくはそれに類する知識を有する人々のみが何かを書くことを許されたサービスということになる。それが悪いというわけではないが、誤りを含む記事を書くこと=アカウント凍結の処分ではいささか厳しすぎるように思える。

悪貨が良貨を駆逐するという事象であったことに異論を唱えるつもりはないが、もしこの決定について単に識者の勝利だと思っている方がいるのであれば、大変危険ではないかと思う。

  1. ある程度であれば不可能ではない

  2. 筆者はこの問題をsyntax-rules側から識別子を挿入してやれば解決できるのではないかと思っていたのだが、そう簡単な問題でもないようである。

  3. こんなマクロを書かないというのでも問題はない。

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?