2012-01-08
■ [ruby] myrurema 0.3.0をリリースしました
最新のbitclustで動かないというレポートをいただいたので(ありがとうございます)直しました。
あとrefeでは「refe Ar i」でArray#indexなどが検索できるというのを知った(思い出した?)ので、それにも対応しました。
/Users/yhara $ rurema Ar ind (1)Array#index (2)Array#indexes (3)Array#indices which one? >
■ [ruby] gem生成ツールをJewelerからBundlerに乗り換えた
BundlerはRubyGemsの依存関係をメンテナンスするツールだけど、実はJeweler等のようにgemを生成するための機能もある。
bundle gemコマンドでひな形を生成することができ、あとはrake buildでpkg/foo-x.y.z.gemができたりとかそういう感じ。
/tmp $ bundle gem foo create foo/Gemfile create foo/Rakefile create foo/.gitignore create foo/foo.gemspec create foo/lib/foo.rb create foo/lib/foo/version.rb Initializating git repo in /private/tmp/foo
既にあるプロジェクトをbundlerに移行したい場合も、まず上のように/tmpにひな形を作ってから、それを参考にGemfile, Rakefile, lib/*/version.rbを書くのが良いと思う。
Jewelerとの違いは以下。
- 生成される*.gemspecがシンプル。
- バージョン名をVERSIONというファイルに書くのではなく、lib/foo/version.rbのFoo::VERSIONという定数から取得する。
- Gemfileを書く必要がある。が、最近のBundlerはGemfileに「gemspec」と書くと*.gemspecのdependencyを見てくれる機能があるので特に手間ではない(例)
(Jewelerもだけど)git前提なのでそこは注意。
■ [scheme] beginで囲まれたdefineに展開されるマクロを書いたときの、定義される変数のスコープについて
BiwaSchemeにInternal defineを実装するために、R6RSの仕様を読んでいる。そこで一点疑問が。
11.4.7 Sequencingによると、 (begin (define ..) (define ..)) みたいなbeginは「spliced into the surrounding body, as if the begin wrapper were not actually present.」のように書いてある。
つまりこういうことができる。
(begin (define a 'a) (define b 'b)) (display a)
ならば、以下のようなこともできるのかと思ったのだけど、そうとは保証されてないみたいだ。
(define-syntax m (syntax-rules () ((_) (begin (define a 'a) (define b 'b) )))) (m) (display a)
てか、beginで囲んだdefineがspliceされるのってこういうことするためだと思ってたんだが、違うのかな。
できなかったやつ
/Users/yhara/proj/biwascheme % /Applications/Racket\ v5.1.1/bin/racket -f _misc/definition.scm reference to undefined identifier: b /Users/yhara/proj/biwascheme % petite _misc/definition.scm Petite Chez Scheme Version 8.4 Copyright (c) 1985-2011 Cadence Research Systems Exception: variable b is not bound /Users/yhara/proj/biwascheme % ypsilon _misc/definition.scm error: unbound variable b ...
できたやつ
/Users/yhara/proj/biwascheme % LARCENY_ROOT=/Users/yhara/research/Scheme/larceny-0.97-bin-native-ia32-macosx larceny -- _misc/definition.scm Larceny v0.97 "Funny in the Head" (Aug 19 2009 04:24:46, precise:Posix:unified) b /Users/yhara/proj/biwascheme % gosh _misc/definition.scm b
これが動いたり動かなかったりするのは begin の問題ではなくて、 hygienic macro とトップレベルの束縛の扱いの問題です。<br><br>まず、上のコードは R6RS ではエラーになります。というのは、 m の中に現れる a と b はマクロ展開時に導入される変数名なので、展開先では rename されて見えなくなるからです。<br>m の引数として変数名を取るようにして<br> (define-syntax m<br> (syntax-rules ()<br> ((_ a b)<br> (begin<br> (define a 'a)<br> (define b 'b)))))<br><br> (m a b)<br>にすれば動きます。<br><br>R5RS の場合だと、処理系によって動いたり動かなかったりします。<br>R5RS では、トップレベルの束縛は未定義のものも含めてすべて束縛済みであるものとして扱ってもよいことになっていて(R5RS 5.2.1)、束縛済みとして扱う処理系では、 m 中の a、 b は束縛済みの a、 b を指すものとして rename されないのに対して(さらに、束縛済みの変数に対する define は set! と同じ意味になります)、そうでない処理系では、 R6RS の場合と同じく新たな変数を導入したものとして a、 b が rename されます。
ありがとうございます。寝る前にベッドで考えてて、「syntax-caseを使えばいけるのではないか?」というところまでは思いついたのですが、マクロ引数に変数名を渡すというのは思いつきませんでした。