【发布时间】:2016-04-14 11:58:00
【问题描述】:
我想将表现出 lambda 行为(参数检查)的过程转换为不表现出 lambda 行为的过程。以下是一个非常人为的示例,但它应该能够理解重点:
目的是创建一个看起来像这样的 DSL:
NumberSeries.perform do
add first_series: -> { natural_numbers.take(10) },
second_series: -> { fibonacci_numbers.take(10) }
end
请注意,natural_numbers 和 fibonacci_numbers 不会作为 DSL 中的参数传递。 add 的实现如下所示:
NaturalNumbersFibonacciNumbers = Struct.new(:natural_numbers, :fibonacci_numbers)
FAMOUS_NUMBER_SERIES = NaturalNumbersFibonacciNumbers.
new(natural_numbers, fibonacci_numbers)
def add(first_series:, second_series:)
first_numbers = FAMOUS_NUMBER_SERIES.instance_eval(&first_series)
second_numbers = FAMOUS_NUMBER_SERIES.instance_eval(&second_series)
first_numbers.zip(second_numbers).map { |x, y| x + y }
end
现在,如果我在 DSL 中将 -> 替换为 proc,它将起作用。但是,保留 lambda,我会得到
ArgumentError: 参数数量错误(1 代表 0)
BasicObject#instance_eval 将 self 生成给 lambda,但 lambda 不需要任何参数。
出于显而易见的原因,我不想使用 Fiddle。
【问题讨论】:
-
instance_exec是否可以代替 - 允许您传递参数(或在这种情况下不传递)? -
我很困惑。为什么不直接用 procs 定义你的 DSL?
add first_series: proc { natural_numbers.take(10) }同样优雅。 -
@matt,是的,
instance_exec成功了。不知道我怎么没想到。即使它没有回答问题,但它解决了原始问题,所以添加它作为答案,如果没有人知道该怎么做,我会接受它。 -
@SergioTulentsev - 对于 Rubist - 是的。一般来说 - 没有。
-
对于这个特定的任务:
&->(*args) { λ.call }。对于一般的lambda,可能会检查λ.parameters并构建相应的proc包装器。唯一的问题是:为什么地球上会有人需要它?