我正试图用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和地图的东西,但使用起来真的很难看。
实现这样的事情的最“红宝石”方式是什么?
答案 0 :(得分:10)
嗯,你说你知道拉链和地图所以这可能没用。 但我会发布以防万一。
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
或者,如果你想转发args:
def combine(a, b, *args, &block)
a.zip(b, *args).map(&block)
end
答案 1 :(得分: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
答案 2 :(得分: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那样。
答案 3 :(得分:0)
您可以将方法的名称作为符号传递,并使用Object#send
(或Object#__send__
)按名称调用它。 (Ruby实际上没有函数,它有方法。)
您可以传递一个lambda
或块,在您想要的参数上调用您想要的方法。传递块可能是首选的Ruby方式,当它工作时(即当你只有一个块传递时)。
您可以通过Method
直接检索Object#method
个对象,然后将它们传递给call
,但我没有这方面的经验,并且在实践中没有看到它做得太多