5

Ruby で関数型プログラミングについて頭を悩ませようとしていますが、適切なドキュメントがあまりないようです。

基本的に、次の Haskell 型シグネチャを持つ結合関数を作成しようとしています。

[a] -> [a] -> (a -> a -> a) -> [a]

そう

combine([1,2,3], [2,3,4], plus_func) => [3,5,7]
combine([1,2,3], [2,3,4], multiply_func) => [2,6,12]

zip と map の使用に関するいくつかの情報を見つけましたが、これは非常に使いにくいと感じます。

このようなものを実装する最も「ルビー」な方法は何でしょうか?

4

4 に答える 4

10

さて、あなたはあなたがzipとmapについて知っていると言ったので、これはおそらく役に立たないでしょう。念のため投稿します。

def combine a, b
    a.zip(b).map { |i| yield i[0], i[1] }
end

puts combine([1,2,3], [2,3,4]) { |i, j| i+j }

いいえ、私もそれが美しいとは思いません。

編集-#ruby-lang @ irc.freenode.netはこれを示唆しています:

def combine(a, b, &block)
    a.zip(b).map(&block)
end

または、引数を転送する場合は、次のようにします。

def combine(a, b, *args, &block)
    a.zip(b, *args).map(&block)
end
于 2009-01-14T19:27:57.030 に答える
3

非常に素朴なアプローチ:

def combine(a1, a2)
  i = 0
  result = []
  while a1[i] && a2[i]
    result << yield(a1[i], a2[i])
    i+=1
  end
  result
end

sum = combine([1,2,3], [2,3,4]) {|x,y| x+y}
prod = combine([1,2,3], [2,3,4]) {|x,y| x*y}

p sum, prod

=>
[3, 5, 7]
[2, 6, 12]

そして任意のパラメータで:

def combine(*args)
  i = 0
  result = []
  while args.all?{|a| a[i]}
    result << yield(*(args.map{|a| a[i]}))
    i+=1
  end
  result
end

編集:私はzip / mapソリューションに賛成しましたが、ここに少し改善があります、それについて醜いものは何ですか?

def combine(*args)
  args.first.zip(*args[1..-1]).map {|a| yield a}
end

sum = combine([1,2,3], [2,3,4], [3,4,5]) {|ary| ary.inject{|t,v| t+=v}}
prod = combine([1,2,3], [2,3,4], [3,4,5]) {|ary| ary.inject(1){|t,v| t*=v}}
p sum, prod
于 2009-01-14T19:22:56.947 に答える
1

Symbol.to_proc ( Raganwaldによるコード)も必要なようです。

class Symbol
  # Turns the symbol into a simple proc, which is especially useful for enumerations. 
  def to_proc
    Proc.new { |*args| args.shift.__send__(self, *args) }
  end
end

これで、次のことができます。

(1..100).inject(&:+)

免責事項: 私は Rubyist ではありません。私は関数型プログラミングが好きです。したがって、これは Ruby らしくない可能性があります。

于 2009-01-16T22:42:31.500 に答える
0

メソッドの名前をシンボルとして渡し、Object#send(またはObject#__send__) を使用して名前で呼び出すことができます。(Ruby には実際には関数はなく、メソッドがあります。)

lambda目的の引数で目的のメソッドを呼び出す or ブロックを渡すことができます。ブロックを渡す方法は、動作する場合 (つまり、渡すブロックが 1 つしかない場合)、おそらく好ましい Ruby の方法です。

Methodオブジェクトを直接取得してObject#methodから渡しますcallが、この方法で行った経験はほとんどなく、実際に行われたことはあまりありません。

于 2009-01-14T19:31:39.347 に答える