Ruby Haskell 化計画

Rubyの配列処理を Haskell 風に記述できる関数を作ってみた。Rubyで Haskell 風のプログラムが作れれば、代入もあるし、IOモナドもないので楽ができる。

ファイル名: haskell.rb

def head(xs) xs.first end
def tail(xs) ys = xs.dup; ys.shift; ys end
def last(xs) xs.last end
def init(xs) ys = xs.dup; ys.pop; ys end
def hconcat(xs) xs.inject([]) {|x,y| x+y} end
def strconcat(xs) xs.join("") end
def hreverse(xs) xs.reverse end
def hsort(xs) xs.sort end
def replicate(n, a) [].fill(a, 0, n) end

def hzip(xs, ys) xs.zip(ys) end
def zipWith(prc, xs, ys) (xs.zip(ys)).map &prc end

def map(prc, xs) xs.map &prc end
def filter(prc, xs) ys = []; xs.each {|x| if prc.call(x) then ys += [x] end}; ys end

def sum(xs) xs.inject(0) {|x,y| x + y } end
def product(xs) xs.inject(1) {|x,y| x * y } end

実行例
C:\Ruby>irb
irb(main):001:0> load "haskell.rb"
=> true
irb(main):002:0> head [1,2,3,4,5]
=> 1
irb(main):003:0> tail [1,2,3,4,5]
=> [2, 3, 4, 5]
irb(main):004:0> hzip [1,2,3], [4,5,6]
=> [[1, 4], [2, 5], [3, 6]]
irb(main):006:0> zipWith proc{|x,y| x+y}, [1,2,3], [4,5,6]
=> [5, 7, 9]
irb(main):008:0> map proc{|x| x*x}, [1,2,3,4,5]
=> [1, 4, 9, 16, 25]
irb(main):010:0> filter proc{|x| x < 4}, [1,2,3,4,5]
=> [1, 2, 3]
irb(main):011:0> sum (1..10)
=> 55
irb(main):012:0> product(1..5)
=> 120

これらの関数を使って新しい関数を定義することもできる。次の例はベクトルの内積を計算する dot 関数を定義している。

irb(main):013:0> def dot(xs,ys) sum( zipWith( proc{|x,y| x*y}, xs, ys )) end
=> nil
irb(main):014:0> dot [1,2,3], [4,5,6]
=> 32

クイックソートもこれらの関数を使ってプログラムできる。

ファイル名: qsort.rb
load "haskell.rb"

def qsort(xs)
  if xs == []
    []
  else
    x = xs.shift
    lt = filter proc{|y| y <= x}, xs
    gt = filter proc{|y| y > x}, xs
    qsort(lt) + [x] + qsort(gt)
  end
end

実行例
irb(main):001:0> load "qsort.rb"
=> true
irb(main):002:0> qsort [5,4,2,1,3]
=> [1, 2, 3, 4, 5]

fib = 0:1:zipWith (+) fib (tail fib) のような遅延評価を使った定義は無理だが、Haskell の関数のかなりの部分を Ruby に移植できるのがわかる。


今日の Haskell
Hugs> mapM putStrLn $ map (flip(replicate) '*') [1..5]
*
**
***
****
*****

mapM は map のモナド版。
[PR]
by tnomura9 | 2010-12-07 18:45 | Haskell | Comments(0)
<< Ruby の関数と副作用 Haskell でバブルソート >>