2013-04-24 51 views
7

如下面的ruby示例所示,我不能调用lambda参数的数量错误ProcMethod创建,因为它严格限制参数的数量:如何将方法或lambda转换为非lambda proc

# 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 

我如何获得一个Proc,是不是无论是从Proc一个lambda是或从Method

+0

据我所知,您不能将方法或lambda转换为非lambda proc。你想达到什么目的? – 2013-04-24 17:51:36

+0

@WallyAltman块的调用语义,首先是关于参数的数量,但还有其他几个不同之处。 – michelpm 2013-04-24 17:58:06

回答

2

没有办法做到这一点。

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

如果你真的需要这样做,你需要建立自己的区块,例如:

Proc.new{ a } 

对于一个更通用的方法,你必须检查方法的arity,只有通过必要的参数。

+0

我想这不太可能是因为'return','next'和'break',作为一种临时措施,我一直在用splat编写方法或使它们返回一个'Proc'。有没有办法证明它不能完成? – michelpm 2013-04-25 19:03:54

+0

@michelpm:没有证据,对不起。 – 2013-04-25 20:45:16

0

尝试在非拉姆达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 
0

转换LambdaProc

这里有一个解决一个封装了lambdamethod中的呼叫Proc和用途图示以处理任意数量的参数:

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或方法调用一个进程没有直接的方法。这只是一种解决方法,明显比实际交易慢(因为将一个呼叫包装在另一个呼叫中)。