Ruby の配列処理のメソッドを拡充する。

Haskell で記述されたプログラムの特徴の一つが、その簡潔さだ。そうして、そのかなりの部分が強力なリスト処理の関数によっているような気がする。Ruby も配列処理関係のメソッドが豊富だが、Haskell のリスト処理の関数を Ruby に持ってくれば、Ruby にも Haskell の記述の簡潔さを導入できるのではないだろうか。

例えば、Haskell の sum は Ruby では次のように定義することができる。

irb(main):001:0> class Array
irb(main):002:1>   def sum
irb(main):003:2>     total = 0
irb(main):004:2>     self.each {|x| total += x }
irb(main):005:2>     total
irb(main):006:2>   end
irb(main):007:1> end

実行例
irb(main):008:0> [1,2,3].sum
=> 6
irb(main):009:0> (1..10).to_a.sum
=> 55

また、zipWith は次のように定義できる。

irb(main):028:0> def zipWith(xs, ys, proc)
irb(main):029:1>   out = []
irb(main):030:1>   n = [xs.length, ys.length].min
irb(main):031:1>   for i in 0...n
irb(main):032:2>     out[i] = proc.call(xs[i], ys[i])
irb(main):033:2>   end
irb(main):034:1>   out
irb(main):035:1> end

実行例
irb(main):036:0> zipWith([1,2],[3,4], proc{|x,y| x + y})
=> [4, 6]

sum と zipWith を組み合わせると、ベクトルの内積 dot(xs, ys) は次のように簡潔にプログラムできる。

irb(main):052:0> def dot(xs, ys)
irb(main):053:1>   zipWith(xs, ys, proc{|x,y| x * y}).sum
irb(main):054:1> end

実行例
irb(main):055:0> dot([1,2], [3,4])
=> 11

zipWith や sum は汎用のメソッドなので、他のメソッドの記述も簡潔になる可能性がある。Haskell の良いとこ取りを Ruby に持ってくるには、配列関係のメソッドを拡充するのが手っ取り早い。動作のオーバーヘッドが問題でない場合は、Haskell のListモジュールの関数を参考に自分用のライブラリを作っておいてもいいかもしれない。

Haskell フィーバーの第二波の記事も今日でおしまいにしたい。プログラムネタばかりを続けるのにも少々疲れてきたからだ。

今度の Haskell マイブームのきっかけは、食塩の一日摂取量の計算に Haskell が使えたことから個人的な用途に Haskell をどうやって使うようにできるだろうかという興味がでたのがきっかけだった。

興味は次にIOモナドへと移り、IOモナドの本質が「一つの引数をとり、IO型を戻り値として返す関数」を>>= 演算子でつないだものだということがわかり、今度はなぜ Haskell の記述が簡潔なのかという疑問がでてきた。

それも、Haskell の強力なリスト処理の関数と、高階関数と、全てを関数で記述するためにモジュール化が容易であることと、再帰関数と、関数のカリー化によるものだということが分かったのでひとごこちついた気分だ。

要点が分かれば、あとは、地道に教科書をよんだり、他人のプログラムを読んだり、ライブラリーをさまよったりという地味なしかし膨大な作業が残っているだけだ。個人的な思考活動を補助してくれるプログラム言語は、Ruby と Haskell で何とかなりそうだし、何より両方共やっていて楽しい。しかし、両方ともそう簡単には使いこなさせてくれなさそうなので、ブログの記事にするのはもう少しマグマが溜まってからにしたい。

なお、Haskell 関係の記事は、Haskell 記事リストタグにまとめておいたので興味をもたれた方は覗いていただければ幸だ。あまり高度な知識はない初心者の立場からの Haskell へのアプローチの記録だ。
[PR]
by tnomura9 | 2010-12-02 02:46 | Haskell | Comments(3)
Commented by ツムジ at 2010-12-02 09:05 x
Ruby には配列の畳み込み処理をする inject というメソッドがあるので、Array#sum はもっと簡単に定義できます。

class Array
def sum
return self.inject(+:)
end
end
Commented by ツムジ at 2010-12-02 09:18 x
さっき気付いたのですが Ruby 1.9 には Array#zip というメソッドもあるようです。
Commented by tnomura9 at 2010-12-02 10:40
ツムジさん、コメントありがとうございました。
inject という畳込みがあったのですね。Array#zipも確認しました。ブロックも引数に取れるのでいろいろできそうです。Rubyの記述がどんどんコンパクトになるのが楽しみです。
<< 地球外生命体 行列の積 >>