トップ 最新 追記

Route 477



2012-01-05

[ruby] 簡単にRuby/Rails界隈の「事情通」になる方法

ブログを読んでいる人から、どこでRuby関係の情報を仕入れているのかと聞かれることが(希に)ありますが、最近の大きな情報源はこれです。

RubyInsideの中の人でもあるPeter Cooper氏のやっているメーリングリストで、登録するとこんな感じのメールが週一で届きます。 あとはタイトルをざっと見て、面白そうなのがあればクリックすると。

日本人で読んでる人まだそんなに多くなさそうなので、ここを情報源に日本語の解説記事なんか書くとけっこう喜ばれるんじゃないかと思います。

ちなみに同じ運営者のJavaScriptWeeklyというのもあって、こっちも面白いです。

(1/13追記:トップページを見たら、HTML5 Weeklyというのもやっているそうです。あと、今日Status Codeという新メルマガのお知らせが来ました。「プログラミング言語によらない話題」ということなので、どんな内容になるのか今から楽しみです。)


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
本日のツッコミ(全2件) [ツッコミを入れる]

leque [これが動いたり動かなかったりするのは begin の問題ではなくて、 hygienic macro とトップレベルの..]

yhara [ありがとうございます。寝る前にベッドで考えてて、「syntax-caseを使えばいけるのではないか?」というところま..]


2012-01-10

[scheme] R6RS Enumerationsに関する調査

というメモが見つかったので貼っておく。


Recordsほどではないがなんか無駄にややこしいような…

参考

ypsilonの実装

 (define-struct enum-type (universe members indexer constructor))
 (define-struct enum-set (type members))

各enum-setはmembers(シンボルのリスト)とtype(enum-type)をもつ。

各enum-typeはuniverse(母集合となるシンボルのリスト)、members(??)、indexer(シンボルから番号を返す手続き)、constructor(シンボルのリストからenum-setを作る手続き)をもつ。

よって、各enum-setは自分の母集合であるシンボルのリストを(enum-type経由で、間接的に)もつ。これを元文書ではenum-setの「universe」と呼んでいる。

enum-setはfirst classのデータ構造である。例えばypsilonでは「#<enum-set (a b c d)>」のように表示される(ypsilonの場合、属するtypeは表示されない)。Larcenyだと単に「#<record enum-set>」のように 表示される。

しかしやっかいなことに、enum-typeはfirst classのデータ構造*ではない*。R6RS Enumerationsでは、各enum-setに対しそのenum-typeを取得するようなAPIは用意されておらず、 Schemeの世界に取り出すことはできない。あるenum-setの母集合を知りたいときは、(enum-set-universe s) として、「sと同じenum-typeに属する、母集合の全ての要素を含んだenum-set」を得るという仕様になっている。また2つのenum-setが同じenum-typeに属しているかどうかを知る方法もない*1

さてそうすると、「どうやってあるenum-typeのenum-setを作るのか?」という疑問がわく。答えは以下。 define-enumerationでenum-typeを定義した場合は、第三引数で指定した名前がenum-setのコンストラクタ(enum-setを生成する手続き)になる。

(define-enumeration color
  (red green black white)
  color-set)

(color-set red black)

もう一つ低レイヤのAPIがあって、(enum-set-constructor s)とすることで、「sと同じenum-typeのコンストラクタ(enum-setを生成する手続き)」を取得することができる。 また(make-enumeration '(a b c))で、universeが(a b c)であるような新しいenum-typeを定義することができる。ただし返り値はenum-typeではなく(前述のようにenum-typeはfirst classではない)、#<enum-set (a b c)>が返る。

制限

以下の操作では、2つのenum-setは同じenum-typeに属していなければならない。

  • (enum-set-union es1 es2) -> enum-set
  • (enum-set-intersection es1 es2) -> enum-set
  • (enum-set-difference es1 es2) -> enum-set

以下の操作では、2つのenum-setは別のenum-typeであってもよい。

  • (enum-set=? es1 es2) -> bool
    • シンボルの集合として等しいかを返す。
    • 両者が別のenum-typeであっても、シンボルの集合として等しければ#tが返る。
  • (enum-set-subset? es1 es2) -> bool
    • es1がes2のサブセットであるとき#tを返す。
    • 両者が別のenum-typeであるときは、universeについても判定が行われる(即ち、es1のuniverseがes2のuniverseのサブセットでなければ#tが返らない)。
  • (enum-set-projection es1 es2) -> enum-set
    • これはむしろes1にes2が異なるタイプを指定するものかな。

マクロ

R6RS Enumerationsはマクロ(構文)を一つ定義する。define-enumerationがそれだ。

ypsilonでは、(define-enumeration type-name (symbol1 ...) constructor-syntax) をsyntax-rulesでdefineとdefine-syntaxに展開し、 展開されたdefine-syntaxではsyntax-caseを使うというちょっとテクニカルな実装になっている*2

まずdefineでconstructorという一時変数にコンストラクタを束縛する。

       (begin
         (define constructor (enum-set-constructor (make-enumeration '(symbol1 ...))))

次に(color red)のような構文を定義する。これが「マクロ展開時に引数がuniverseに含まれているかのチェックを行うこと」という定義があるので、syntax-rulesではなくsyntax-caseを使わないと書けないんだよね。symbol2はこの例でいう'red。(symbol1 ...)はenum_type定義時のuniverse。(_ symbol2) はパターンマッチで、(type-name symbol2)と書いてもいいんだけど、このsyntax-caseが使われる時点で 最初の要素はtype-nameにマッチするに決まっているから、ワイルドカード「_」を指定している。syntax-case/rulesではおなじみのイディオム。

(color red)は何をするかというと、単に'redを返す。それだけ。 ただし引数がuniverseに入ってるかはチェックするので、(color asdf)とかはエラーになる。 (正直使いどころがよく分からない…(color purpel)みたいにtypoしたときにエラーになるから 安全ですよ、ということかな)

         (define-syntax type-name
           (lambda (x)
             (syntax-case x ()
               ((_ symbol2)
                (or (memq (syntax->datum (syntax symbol2)) '(symbol1 ...))
                    (syntax-violation 'type-name "excpectd symbols which belong to the universe" x))
                (syntax 'symbol2)))))

最後に(color-set red black)のような構文を定義する。

         (define-syntax constructor-syntax
           (lambda (x)
             (syntax-case x ()
               ((_ symbol3 (... ...))
                (or (for-all (lambda (e) (memq e '(symbol1 ...)))
                             (syntax->datum (syntax (symbol3 (... ...)))))
                    (syntax-violation 'constructor-syntax "excpectd symbols which belong to the universe" x))
                (syntax (constructor '(symbol3 (... ...))))))))))))

*1 いや、(enum-set-union s1 s2)としてエラーがでるかで無理やり判別はできるが

*2 いや、Scheme的に普通かも知れないが

[scheme] Mac上にいろいろなR6RSインタプリタをインストールする (2012/01版)

R6RSのサイトに実装へのリンクがある。

Homebrewで入れられるもの

(MacPortsにもいろいろパッケージがあると思いますが、使ってないので省略)

Ypsilon
$ brew install ypsilon
$ ypsilon foo.scm
mosh
$ brew install mosh
$ mosh foo.scm

パッケージがあるもの

Chez Scheme

商用だが、フリー版の「Petite Chez Scheme」がある。

http://www.scheme.com/download/ から「Petite Chez Scheme」「32bit or 64bit」「threaded or nonthreaded」 「Petite Chez Scheme for Intel/AMD MacOS X」「*.pkg(インストーラ) or *.tar.gz(ソース)」を選ぶ。

今回はpcsv8.4-i3osx-1.pkg.tar.gzを選んだ。インストーラに従うと/usr/bin/petiteがインストールされる。

PLT Racket

brewでも入るけど、インストーラでバイナリを入れる方が簡単だったような。

起動

$ /Applications/Racket\ v5.1.1/bin/racket -f foo.scm
Larceny

http://www.larcenists.org/download.html から「prebuilt for Macintosh OS X/IA32」をダウンロード。

起動

LARCENY_ROOT=/Users/yhara/research/Scheme/larceny-0.97-bin-native-ia32-macosx larceny -- foo.scm

その他

Ikarus

開発が止まっていて、Vicareに引き継がれてるらしい。Vicareも6月からコミットがないが…

Guile
$ brew install guile

で入るんだけど、使い方がよく分からない…(そもそもどの程度R6RS準拠なのか)

$ echo '(import (rnrs (6)))' | guile
guile> 
Backtrace:
In standard input:
   1: 0* (import (rnrs (6)))

standard input:1:1: In expression (import (rnrs #)):
standard input:1:1: Unbound variable: import
ABORT: (unbound-variable)
guile>     
IronScheme

未トライ http://ironscheme.codeplex.com/

BiwaScheme (おまけ)
$ brew install node
$ brew install npm
Error: No available formula for npm
npm can be installed thusly by following the instructions at
  http://npmjs.org/

To do it in one line, use this command:
  curl http://npmjs.org/install.sh | sh
$ curl http://npmjs.org/install.sh | sh
$ npm install biwascheme