Как конвертировать метод или лямбду в не лямбда-процесс

Как показано в примере с рубином ниже, я не могу назвать lambda с неправильным количеством аргументов как Proc создан из Method потому что строго по количеству аргументов:

# 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 то есть или от Method?

3 ответа

Решение

Нет способа сделать это.

Помимо передачи аргумента, мне интересно, что вы ожидаете от return в методе. Это может вести себя только в lambda путь...

Если вам действительно нужно это сделать, вам нужно будет построить свой собственный блок, например

Proc.new{ a }

Для более общего способа вам придется проверить arity метода и передать только необходимые параметры.

Попробуйте обернуть его не лямбда 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

Перерабатывать Lambda в Proc

Вот обходной путь, который оборачивает lambda или method позвонить в Proc и использует 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!"

Примечание: не существует прямого способа преобразовать лямбда или вызов метода в процедуру. Это просто обходной путь и, очевидно, медленнее, чем реальная сделка (из-за оборачивания одного вызова в другой).

Другие вопросы по тегам