sort コマンドの実装(その2)を読んで、単なる「引数に対する操作を表すオブジェクト」のためにクラスを定義する意味が分かんね、と思っていろいろ書いてみたらこうなった。
require 'optparse'
module Ordering
def cartesian(rhs)
proc {|(a0,*ar), (b0,*br)|
result = self.call(a0, b0)
result == 0 ? rhs.call(ar, br) : result
}.extend(Ordering)
end
def composite(rhs)
proc {|a,b| self.call(rhs.call(a), rhs.call(b)) }.extend(Ordering)
end
def scalar_prod(rhs)
case rhs
when -1 then -self
when 0 then NULL
when 1 then self
else raise ArgumentError, "must be -1, 0, or 1"
end
end
def -@
proc {|a,b| -self.call(a,b)}.extend(Ordering)
end
def *(rhs)
case
when rhs.respond_to?(:call)
case rhs.arity
when 1 then self.composite(rhs)
when 2 then self.cartesian(rhs)
end
when -1, 0, 1
scalar_prod(rhs)
else
raise TypeError
end
end
def coerce(lhs)
case lhs
when -1, 0, 1 then [self, lhs]
else super
end
end
DEFAULT = proc{|a,b| a <=> b}.extend(Ordering).freeze
ennumeric = proc{|x| /^(\d*|\s+\d+)(.*)$/ =~ x; [$1.to_i, $2]}
NUMERIC = (DEFAULT*DEFAULT*ennumeric).freeze
NULL = proc{|a,b| 0}.extend(Ordering).freeze
end
sort = Ordering::DEFAULT
reverse = 1
opt = OptionParser.new
opt.on("-n", "--numeric-sort") {|v| sort = Ordering::NUMERIC }
opt.on("-r", "--reverse") {|v| reverse = -1}
opt.parse!(ARGV)
ARGF.sort(&reverse*sort).each{|v| print v}
結局、sort(1)だのyes(1)だの、uniq(1)だの、この手のUnixのUnixたるところを示す典型的フィルタコマンドは関数型言語のほうが綺麗に書けるんだろうな。Rubyだといまいちぱっとしない。むやみにProcにメソッド追加するのもアレだし、かといってlambda相当物はProc以外にないので苦労している。それでも、こんな風にソート処理を分解しておけば、あとから-f (--ignore-case)オプションを追加しようと思ったとしても、proc{|x| x.downcase}を掛けるだけだから拡張が簡単である。
一応、上のコードは、ソート関数を「要は全順序だろ」と思って係数体が{-1, 0, 1}のベクトル空間と見なすやりかただな。えっと比較対象の行に対する逆元をうまく定義できるとすれば、線形性は満たすよな。ただ、辞書式順序をcartesianと名付けたのはちょっと不正確か? 線形写像のカルテシアン積の、その{-1, 0, 1}への線形な写像だよな。
久々にcoerce規約を実装して楽しかった。でも、これHaskellならずっと綺麗に書けるだろう。むー。
昨日告知を出した訳ですが、RubyKaigi2008の会場でRuby技術者認定試験が実施されます。CTCがやってる、例のRubyアソシエーション認定プログラマの試験です。
などなど、是非受けてみてください。RubyKaigi会場で受験した方には、もれなく限定グッズがついてきます。グッズを作るのに使いたいと言われてCTCにRubyKaigi2008のロゴを送ったので、たぶんRubyKaigi2008公式ロゴをあしらったレアものだと思います。それも、たぶんTシャツとかタオルとかありがちなものじゃなくて。CTCさんから「グッズって何が良いのかな?」と聞かれて、「Tシャツはありがちだし、意外と見せびらかすのが難しいからつまらないですよね。タンブラーとかマグカップとか?」と答えたので。
この限定グッズを貰えるのはRubyKaigi会場受験者だけっ。私もグッズ欲しいので、スタッフの仕事をちょっとさぼって受けるつもり。なーに、20日の設営作業に直接組み込まれている訳じゃないので、90分ぐらい私がいなくても誰も気づかないだろう。
なお、受験するためには6/17までに予約の必要があります。当日の受験申し込みは受け付けていないのでご注意を。また試験は6/20に3回実施しますが、定員になり次第申し込みを締め切るらしいです。あと、「実施するのは6/20だけ」「メインセッションを開催する6/21, 22には試験はない」というのも注意ね。
詳しくは告知ページを参照してください。
明日、5月10日(土)の10:00から日本Ruby会議2008のチケット販売が始まる。過去の例では1時間以内に売り切れるので購入はお早めに。
私もスピーカーとして話す。「RSpecによるRailsアプリケーションBDD事例」というタイトルで、1日目に。技術的にはつまんない話で、ほんのちょっとしたTipsを紹介する程度のもの。ただ、一応小さなところとはいえこういう風に開発を実践した事例がありますよ、というレポートしたくて申し込んだら通ったのだった。
今年のRubyKaigiは全部で3日間。会場はつくば国際会議場で、
の3カ所を利用する。
6月20日(金)は、イベントは多目的ホールのみ。その日は大ホールはスタッフが設営作業中なのだ。ただ、ね。小会議室でもなんかやるかも、ですよ。
で、多目的ホールでは3日間、スポンサー企業やコミュニティがブースを出してる。見に行くと面白いと思う。Rails勉強会@東京でもブースを出すのだけれども、常連参加者による「舞波に聞け!」とか「Railsよろず相談室」とかそんな感じの企画をやってると思う。
そんな感じで、20日は「1日がかりの前夜祭」という雰囲気も漂いつつ「第0日目」と呼ばれている。スタッフが「第×日目」と言ったら基本的には0-baseで、ただし偶に1-baseのこともあるのでご注意を。
ちなみに、多目的ホールへの入場にはチケットは要らない。
6月21日(土)から大ホールでのメインセッションが始まる。私もメインセッションでこの日に喋る。チケットが要るのはこっちのメインセッションを聞きたい場合ね。
で、その裏では多目的ホールでサブセッションもやってる。申し込み状況を見ると、サブセッションのほうが技術的に濃い話は多い感じ。そういうのを求めているなら、サブセッションを見に行った方が良いかも。いや、メインセッションが全部スーツな話であるとか、そういうわけでもないんだけれども。
21日の夜には懇親会も開かれる。懇親会のチケットは別売りなので、参加したい人はこれも押さえないといけない。
この手のイベントの価値は半分ぐらいは懇親会にあるので、参加しないのはもったいないと言える。海外から来たスピーカーも含めて、いろんな人と会って話をする絶好の機会だから。
この日は引き続きメインセッション・サブセッションが行われる。
今回の会場は筑波ということで、ちょっと東京からは離れてる。筑波は元々宿がそんなにないし、その上RubyKaigi期間中は既にかなり埋まっている。
でも、つくばエクスプレスのおかげで秋葉原から1時間で会場に着くようになった。だから、秋葉原に泊まるというのも選択肢の1つだと思う。秋葉原なら安くて良い宿も見つかりやすいし。