【发布时间】:2021-08-14 00:47:44
【问题描述】:
我正在研究 Ruby 中的函数模型,但遇到了一个问题。我能够成功地将任意给定数量的参数传递给任意函数,如下所示:
add = ->(x, y) { return x + y }
mul = ->(x, y) { return x * y }
def call_binop(a, b, &func)
return func.call(a, b)
end
res = call_binop(2, 3, &add)
print("#{res}\n") #5
res = call_binop(3, 4, &mul)
print("#{res}\n") #12
但是,我无法传递任意数量的函数:
dbl = ->(x) { return 2 * x }
sqr = ->(x) { return x * x }
def call_funccomp(a, &func1, &func2)
return func2.call(func1.call(a))
end
res = call_funccomp(3, &dbl, &sqr)
print("#{res}\n") #Expect 36 but compiler error
编译器错误为syntax error, unexpected ',', expecting ')'
我已经将 lambdas 和 procs 添加到一个数组中,然后执行了数组的元素,所以我知道我可以通过传递这样一个数组作为参数来解决这个问题,但对于简单的情况,这似乎是一个扭曲某些东西(我希望)在该语言中是合法的。 Ruby 是否真的限制了参数列表中可以传递的数量或 lambda?它似乎有一个相当现代、灵活的功能模型(符号有点奇怪),其中事情可以通过call 方法执行。
【问题讨论】:
-
@alf 我不同意关闭,链接的答案是硬连线使用两个 procs/lambdas。有一个更通用的解决方案(当它关闭时我正在发布)。
def call_funccomp(a, *funcs); funcs.each { |f| a = f.call(a) }; a; end;例如,call_funccomp(3, dbl, sqr)为 36,call_funccomp(3, dbl, sqr, dbl)为 72。 -
我的问题与链接的问题不同,但我可以使用那里发布的解决方案。另外(我会尝试一下),我可以使用您在此处发布的那个。谢谢。 Ruby 的功能方面对我来说似乎并没有遵循“原则或最不意外”。例如,我所看到的所有内容都使用了 &func 和 func.call() 语法,这在本示例中失败了。我还没有在任何地方看到 func 和 func.() 记录,更糟糕的是,它可以工作,这意味着它的行为不同。您可能知道我在哪里可以获得明确的 Ruby 文档吗?不是那种“嘿,看看编程有多简单”吗?
-
@PoissonAerohead
&block语法在编程语言中是相当反常的。该语言确实是硬连线的,每个方法只接受一个块。即使方法不期望它,您也可以传递一个块(该方法不会对它做任何事情,但这不是语法错误)。如果您需要将多个可执行代码块传递给一个方法,请使用常规 procs/lambdas,如 pjs 所述。 -
@PoissonAerohead 在搜索时,我找到了this blog。看起来功能组合已明确添加到 Ruby 2.6。基于此,您可能更喜欢的另一个解决方案是:
dbl = ->(x) { 2 * x }; sqr = ->(x) { x * x }; composition = dbl >> sqr; puts composition.call(3)。>>可以被链接起来,所以composition = dbl >> sqr >> dbl在以 3 作为参数调用时将产生 72。 -
@PoissonAerohead 您可以将
yield转为&block,顺便说一句。 “这让你认为你正在像一个普通的论点一样传递它,但你不是” - 如果你用&传递它,你不是。你没有用这个印记装饰其他论点,所以它显然不仅仅是一个普通的论点。
标签: ruby functional-programming