トップ 最新 追記   RSS 1.0 FEED  

Journal InTime


2012-03-09 (Fri) [長年日記]

_ [Ruby] パターンマッチの構文

pattern-matchというライブラリで赤黒木を実装してみてパターンマッチの便利さを改めて実感したが、やはり言語レベルのサポートがあった方がよいと感じたので構文を考えてみた。

  • 既存の構文の互換性は維持する。
  • 新しい予約語を追加しない。

という方針を立てて考えると、case式を拡張するのがよさそうだ。

Haskellのcase式を参考にしてみよう。Haskellでは赤黒木のbalanceを以下のように書くことができる。

balance :: RB a -> a -> RB a -> RB a
balance left key right =
  case (left, key, right) of
    ((T R a x b), y, (T R c z d)) -> T R (T B a x b) y (T B c z d)
    ((T R (T R a x b) y c), z, d) -> T R (T B a x b) y (T B c z d)
    ((T R a x (T R b y c)), z, d) -> T R (T B a x b) y (T B c z d)
    (a, x, (T R b y (T R c z d))) -> T R (T B a x b) y (T B c z d)
    (a, x, (T R (T R b y c) z d)) -> T R (T B a x b) y (T B c z d)
    (a, x, b) -> T B a x b

(a, x, b) -> T B a x bの部分はλ抽象に似ている(Haskellでは\x -> x + 1のようにRubyとは->の位置が違う点に注意)。

Rubyでもstabby lambda風の構文を導入してはどうだろうか。

def balance(left, key, right)
  case [left, key, right]
    -> [R[a, x, b], y, R[c, z, d]] { R[B[a, x, b], y, B[c, z, d]] }
    -> [R[R[a, x, b], y, c], z, d] { R[B[a, x, b], y, B[c, z, d]] }
    -> [R[a, x, R[b, y, c]], z, d] { R[B[a, x, b], y, B[c, z, d]] }
    -> [a, x, R[b, y, R[c, z, d]]] { R[B[a, x, b], y, B[c, z, d]] }
    -> [a, x, R[R[b, y, c], z, d]] { R[B[a, x, b], y, B[c, z, d]] }
    -> * { B[left, key, right] }
  end
end

これなら新しい予約語は必要ないし、->の位置にwhenが来た場合は現状どおりの動作とすれば互換性の問題もない。 endと{}が混ざるのが気持ち悪ければ代りにdo endを使えばよい(stabby lambdaと同じ)。

あと、pattern-matchではextractというメソッドでオブジェクトを分解しているけど、ちょっと名前が一般的すぎる気がするのでdeconstructとかにした方がいい気がする。

_ [Ruby] Enumerable#lazy

yhara先生が提案していたEnumerable#lazyがtrunkに入ったので、喜び勇んで以下の例を試したのだが、なぜかぜんぜん返って来ない。

def pythagorean_triples
  (1..Float::INFINITY).lazy.flat_map {|z|
    (1..z).flat_map {|x|
      (x..z).select {|y|
        x**2 + y**2 == z**2
      }.map {|y|
        [x, y, z]
      }
    }
  }
end
p pythagorean_triples.take(10)

確認したら、どうもEnumerable::Lazyはflat_mapをサポートしていないようだったので、適当に実装してtrunkにcommitしてやった。 こういうことができるのがRubyのいいところだ。というわけで無事動くようになった。

$ ruby-trunk t.rb
[[3, 4, 5], [6, 8, 10], [5, 12, 13], [9, 12, 15], [8, 15, 17], [12, 16, 20], [7, 24, 25], [15, 20, 25], [10, 24, 26], [20, 21, 29]]

しかし、今のEnumerable::Lazy#flat_mapではブロックの値が配列であることを期待するので、以下のようなコードだと残念なことになってしまう。

$ cat t2.rb
def pythagorean_triples
  (1..Float::INFINITY).lazy.flat_map {|z|
    (1..z).lazy.flat_map {|x|
      (x..z).lazy.select {|y|
        x**2 + y**2 == z**2
      }.map {|y|
        [x, y, z]
      }
    }
  }
end
p pythagorean_triples.take(10)
$ ruby-trunk t2.rb
[#<Enumerable::Lazy: #<Enumerator::Generator:0x214bd630>:each>, #<Enumerable::Lazy: #<Enumerator::Generator:0x214bd4c8>:each>, #<Enumerable::Lazy: #<Enumerator::Generator:0x214bd360>:each>, #<Enumerable::Lazy: #<Enumerator::Generator:0x214bd1f8>:each>, #<Enumerable::Lazy: #<Enumerator::Generator:0x214bd090>:each>, #<Enumerable::Lazy: #<Enumerator::Generator:0x214bcf28>:each>, #<Enumerable::Lazy: #<Enumerator::Generator:0x214bcdc0>:each>, #<Enumerable::Lazy: #<Enumerator::Generator:0x214bcc58>:each>, #<Enumerable::Lazy: #<Enumerator::Generator:0x214bcaf0>:each>, #<Enumerable::Lazy: #<Enumerator::Generator:0x214bc988>:each>]

eachでばらしてyieldするようにすればいいかなと思ったのだが、試しに実装したらSEGVしてしまったのでいつかリベンジしよう。

本日のツッコミ(全2件) [ツッコミを入れる]

_ k_tsj [APIは試行錯誤している段階なのでこういう意見は参考になります。 ありがとうございます。]

_ shugo [こちらこそ面白いライブラリをありがとうございます。言語自体に同様の機能が入るとしても当分先だと思いますので、期待して..]


2012-03-12 (Mon) [長年日記]

_ [] 好きな食べ物

だんだん子供が大きくなってきて、色々な質問を受けるようになってきた。「宇宙はどうやって出来たの」とか「死んだらどうなるの」とか「生き物は何で生まれたの」みたいな重い質問もあれば、「お父ちゃんの好きな色は?」といった他愛のないものもある。ときどき「お父ちゃんの好きな食べ物は?」と聞かれると、何となくたこ焼きと答えている。

考えて見れば、大人になってから改まって好きな食べ物を聞かれる機会はめったになくなったような気がするが、子供の頃はことあるごとにこういったやり取りがあったように思う。例えば文集のネタとしては、将来なりたい職業などとともに定番の設問だろう。小学校の文集ではたこ焼きではなく、迷った末にステーキと書いていたのだが、当時クラスメートだった某有名製陶会社の社長の息子がカレーと書いているのを見て、ハンマーでガツンと殴られたような衝撃を受けたのを覚えている。ああ、やっぱりお金持ちの子は違うな、ステーキなんて書いた自分は何て浅ましいのだろう、と思ったものだ。実家ではなぜか毎週土曜日の昼はカレーと決まっていて(祖父が軍隊にいたせいかもしれない)、母親が作る甘ったるいカレーにはほとほとうんざりしていたので、なおさらカレーという回答に衝撃を感じたのだが、今思えば好きな食べ物がカレーというのはごく普通の回答かもしれない(ここで「僕はカレー」「私、ハンバーグ」「さあ、たいへん。ああ、そうだ、これこれ、オリエンタルのハンバーグカレー」というCMのフラッシュバック)。

そういった経験も影響して、最近はたこ焼きという庶民的な食べ物を答えているのかもしれないが、よく考えるとたこ焼きはカレーよりはステーキに近いカテゴリの食べ物であるようだ。つまり、カレーがケの食べ物であるのに対し、ステーキやたこ焼きはハレの食べ物だということだ(少なくとも僕にとっては)。好きな食べ物を聞かれた時にどちらのカテゴリの食べ物を答えるかによって、その人の食べ物に対する基本的なスタンスを垣間見ることができるのかもしれない。


2012-03-13 (Tue) [長年日記]

_ [Ruby] Asakusa.rb参加

たまたま出張が入ったのでAsakusa.rbに行ってきた。

ささださんのところの学生さんの発表で、サーバサイドからRubyでブラウザ上のJavaScriptを呼び出すフレームワーク(?)の話を聞いて面白かった。 RJSに似てるけど、もっとやり取りの粒度が細かくて、ブラウザ側では一切JavaScriptコードをユーザが書かなくていいのが特徴。 リモートオブジェクトの参照をテーブルで管理してて、現状ではテーブルから削除しないそうなので、実用化するにはそのあたりを何とかしないといけなさそう。 RubyのファイナライザからJavaScriptを呼び出してテーブルからエントリを削除するとかかなあ。毎回呼ぶと遅そうだけど。 dRubyはたしか一定時間アクセスがないオブジェクトをテーブルから削除してた気がするけど、そんなのでも問題ないのかな。

あと、松田さんたちから何か話せと言われたので、Enumerable::Lazyが入った話をしてきたけど、Asakusa.rbの猛者たちでも意外とどういうものか理解してなかったので、一般の人たちがちゃんと使えるか不安になってきた。 flat_mapの実装でrb_block_callを入れ子で呼ぶとSEGVするとささださんに文句をいったけど、後でデバッグしたら単にrb_funcallとrb_funcall2を間違えてたせいだった。ごめんなさい。やっぱりCは死ぬべき。


2012-03-18 (Sun) [長年日記]

_ [バイク][KLX125][買い物] バイクスタンド

バイクスタンド

ずっとKLX125のチェーン掃除は車用のジャッキでスイングアームの右側だけジャッキアップして行っていたのだが、ジャッキがヘタってきてなかなか上がならくなってきたので、オフロード用のバイクスタンドを購入した。

DRCのやつは高いのでアストロプロダクツのを買おうかなと思っていたのだが、ストレートというメーカーでもっと安いのがあったのでそちらにした。 最低高さ245mmなので、アンダーガードを付けたままでもちゃんと入る。

最初、駐車場の微妙な傾斜のせいでリアがなかなか上がらなかったが、バイクの向きを変えてフロントが低くなるようにしたら余裕で上がった。

というわけで、ひさびさにチェーンを掃除して大分きれいになった。

チェーン

しかし、あちこち錆びてきてるなあ…。もうちょっとマメに手入れをしなければ。

チェーン調整もしたかったけど、サイズ22のレンチとか替えの割ピンとか色々道具が足りないのでまた今度にしよう。


2012-03-20 (Tue) [長年日記]

_ [バイク][KLX125] チェーン調整

割りピン

今日はホームセンターで22のソケットと割りピンを購入してチェーンの調整をした。

規定値は25mm〜40mmらしいけど、延びまくっていたのでだいたい30mmくらいに調整。目盛とネジ山の数を参考にだいたい左右を合わせたけど、いまいち自信がない。 割りピンはホームセンターにあった3x30だとちょっと長かったけど、まあ、いいか。