Gaucheのlambda shorter-namesをR6RSで実装する
lambdaのshorter-name( http://blog.practical-scheme.net/gauche/20100428-shorter-names )は便利な機能なので、nmoshにはコッソリ入れておくことにする。
^
^は以前reader macroで実装していたのを、単にsyntax-rulesに変更した。
(define-syntax ^ (syntax-rules () ((_ args ...) (lambda args ...))))
以前( http://d.hatena.ne.jp/mjt/20091207/p1#c1260348087 )のコードそのまま。
^x
会社で使っているnmoshでは、この機能をexpanderを変更する形で実装している。というのも、syntax-rulesでは新たなシンボルの導入が事実上できないので、このような"本来存在しない"シンボルを導入するのはsyntax-rulesの範囲では行えない。
R6RSはsyntax-caseが有るので、原理的にはsyntax-caseで対応することができる。
まず、^aを作ってみる。
(define-syntax ^a (lambda (x) (syntax-case x () ((k args ...) (with-syntax ((name (datum->syntax #'k 'a))) #`(lambda (name) args ...))))))
これはR6RS 12.6のサンプルから採ってきた。
あとは、これを26x2個コピペしても良いが、我々は文明人なのでマクロを使う。
(define-syntax define-onechar-lambdas (lisp-transformer (lambda (f) (define (entry name) (let ((namestr (symbol->string name))) `(define-syntax ,(string->symbol (string-append "^" namestr)) (lambda (x) (syntax-case x () ((k args ...) (with-syntax ((larg (datum->syntax #'k (quote ,name)))) #'(lambda (larg) args ...)))))))) (let ((l (cdr f))) (cons 'begin (map entry l)))))) (define-onechar-lambdas a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z)
lisp-transformerはLisp風マクロのためのtransformerで、この定義もR6RS 12.6に有る。
いわゆるControl-charと見間違う罠が有るが、mapやfor-eachのような関数を取る関数には非常に便利。
syntax-caseで実装すると、1文字分に一つlambdaが出来てもったいないという問題以外に、^hogehogeのような複数文字に対応するのが面倒という問題が有る。会社のnmoshにはシンボルの再解釈機能をパーサに仕込んでいて、それを使って ^ 文字をリパースすることで一種のリードマクロを実現している(ちなみに、この機能を使ってキーワード構文も実装している)。
複数文字はサポートしないので[ ]による記述を推奨したい。
prism:~ oku$ nmosh nmosh top program nmosh> (map (^[target] (+ 1 target)) '(1 2 3)) (2 3 4)