在 ruby 中将函数作为参数传递
Posted
技术标签:
【中文标题】在 ruby 中将函数作为参数传递【英文标题】:passing functions as arguments in ruby 【发布时间】:2010-10-01 10:51:01 【问题描述】:我正在尝试用 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 的东西,但感觉真的很难用。
实现这样的东西最“红宝石”的方式是什么?
【问题讨论】:
【参考方案1】:嗯,你说你知道 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
不,我也不觉得它漂亮。
edit - #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
【讨论】:
【参考方案2】:一个非常幼稚的方法:
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
【讨论】:
【参考方案3】:听起来你可能还想要 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。
【讨论】:
您的代码是正确的,但它只是组成了这一部分:|x, y| x+y 写起来更快(并且可以说更具可读性)。但是您仍然缺少组合和收集部分。【参考方案4】:您可以将方法的名称作为符号传递,并使用Object#send
(或Object#__send__
)按名称调用它。 (Ruby 没有真正的函数,它有方法。)
您可以传递lambda
或块,它在您想要的参数上调用您想要的方法。传递块可能是首选的 Ruby 方式,当它起作用时(即当你只有一个块要传递时)。
您直接通过Object#method
检索Method
对象,然后将它们传递给call
它们,但我没有这样做的经验,也没有看到它在实践中做得太多。
【讨论】:
以上是关于在 ruby 中将函数作为参数传递的主要内容,如果未能解决你的问题,请参考以下文章
如何在 CoffeeScript 中将两个匿名函数作为参数传递?