如何将方法或 lambda 转换为非 lambda proc

Posted

技术标签:

【中文标题】如何将方法或 lambda 转换为非 lambda proc【英文标题】:How to convert method or lambda to non-lambda proc 【发布时间】:2013-04-18 07:18:46 【问题描述】:

如下面的 ruby​​ 示例所示,我不能调用带有错误数量的参数的 lambda,因为它对参数数量非常严格:

# method with no args
def a; end

instance_eval(&method(:a))
# ArgumentError: wrong number of arguments (1 for 0)

method(:a).to_proc.call(1, 2, 3)
# ArgumentError: wrong number of arguments (3 for 0)

method(:a).to_proc.lambda?
# => true

如何从ProcMethod 获得不是lambda 的Proc

【问题讨论】:

据我所知,您不能将方法或 lambda 转换为非 lambda proc。你想完成什么? @WallyAltman 块的调用语义,首先是关于参数的数量,但还有其他一些区别。 【参考方案1】:

没有办法做到这一点。

除了参数传递之外,我想知道您对方法中的return 有什么期望。它只能以lambda 方式运行...

如果你真的必须这样做,你将需要构建自己的块,例如

Proc.new a 

对于更通用的方法,您必须检查方法的arity 并仅传递所需的参数。

【讨论】:

我想这不太可能因为returnnextbreak,作为临时措施,我要么用 splat 编写方法,要么让它们返回 Proc。有没有办法证明做不到? @michelpm:没有证据,抱歉。【参考方案2】:

尝试将其包装在非 lambda Proc 中,如下所示:

l = lambda |a,b| puts "a: #a, b: #b" 
p = proc |a,b| l.call(a,b) 

l.lambda?
#=> true
l.arity
#=> 2
l.call("hai")
#=> ArgumentError: wrong number of arguments (1 for 2)
l.call("hai", "bai", "weee", "womp", "woo")
#=> ArgumentError: wrong number of arguments (5 for 2)

p.lambda?
#=> false
p.arity
#=> 2
p.call("hai")
#=> a: hai, b: 
p.call("hai", "bai", "weee", "womp", "woo")
#=> a: hai, b: bai

【讨论】:

【参考方案3】:

Lambda 转换为Proc

这是一种解决方法,它在 Proc 中包装了 lambdamethod 调用,并使用 splat 处理任意数量的参数:

def lambda_to_proc(lambda)
  Proc.new do |*args|
    diff = lambda.arity - args.size
    diff = 0 if diff.negative?
    args = args.concat(Array.new(diff, nil)).take(lambda.arity)

    lambda.call(*args)
  end
end

无论传递多少参数,这总是有效的;额外的参数将被删除,nil 将替换缺少的参数。


示例:

# lambda with two args
some_lambda = -> (a,b)  [a, b] 

# method with no args
def some_method; "hello!"; end

lambda_to_proc(some_lambda).call(5)
# => [5, nil]

lambda_to_proc(method(:some_method)).call(1,2,3)
# => "hello!"

注意:没有直接的方法可以将 lambda 或方法调用转换为 proc。这只是一种解决方法,显然比真正的交易慢(因为将一个调用包装在另一个调用中)。

【讨论】:

请记住,如果您的 lambda 可以采用默认参数,这将不起作用。例如。 some_lambda = -> (a, b = 0) [a, b] 在使用 lambda_to_proc 调用时会引发 ArgumentError。一种解决方法是使用lambda.parameters.length 而不是lambda.arity

以上是关于如何将方法或 lambda 转换为非 lambda proc的主要内容,如果未能解决你的问题,请参考以下文章

如何将错误处理方法转换为 Lambda 函数

将多级 for 循环转换为 linq 或 lambda 表达式

如何从 PostgreSQL 查询转换为 LINQ 或 lambda 表达式

如何使用Lambda从Amazon AWS中提取和转换单个dynamodb元素

如果不首先将 lambda 表达式转换为委托或表达式树类型,则无法将 lambda 表达式用作动态分派操作的参数

C# 如何使用 lambdas 或其他方法使用来自不同列表的值初始化列表 - 需要简化