Proc.arity против Lambda.arity - программирование
Подтвердить что ты не робот

Proc.arity против Lambda.arity

Почему proc и лямбда возвращают разные значения для arity?

например.

proc   { |x = 0| }.arity       #=> 0
lambda { |a = 0| }.arity       #=> -1
proc   { |x=0, y| }.arity      #=> 1
lambda { |x=0, y| }.arity      #=> -2

Смотрите: http://www.ruby-doc.org/core-2.0/Proc.html#method-i-arity

4b9b3361

Ответ 1

В документах, к которым вы привязались:

Возвращает количество аргументов, которые не будут игнорироваться. Если объявлен блок без аргументов, возвращается 0. Если известно, что блок принимает ровно n аргументов, возвращает n. Если блок имеет необязательные аргументы, возвращаем -n-1, где n - количество обязательных аргументов. Прок без объявления аргументов - это тот же самый блок, объявляющий || как его аргументы.

То, что doc забывает упомянуть, заключается в том, что procs и лямбда не обрабатывают аргументы точно так же, как например:

>> p = proc { |a = 1, b| b }
=> #<Proc:[email protected](irb):1>
>> l = lambda { |a = 1, b| b }
=> #<Proc:[email protected](irb):2 (lambda)>
>> p.call
=> nil
>> l.call
ArgumentError: wrong number of arguments (0 for 1..2)
    from (irb):2:in `block in irb_binding'
    from (irb):4:in `call'
    from (irb):4
    from /usr/local/bin/irb:12:in `<main>'

Изменить: язык программирования Ruby от O'Reilly - это тот, у которого немного больше деталей:

6.5.3 Arity of Proc

Арктичность proc или лямбда - это количество аргументов, которые она ожидает. (Слово происходит от суффикса "ary" унарного, двоичного, тернарного, и т.д.) Объекты Proc имеют метод arity, который возвращает количество аргументы, которые они ожидают. Например:

lambda{||}.arity # => 0. No arguments expected
lambda{|x| x}.arity # => 1. One argument expected
lambda{|x,y| x+y}.arity # => 2. Two arguments expected

Понятие arity запутывается, когда Proc принимает произвольное количество аргументов в окончательном аргументе * -prefixed. Когда Proc допускает необязательные аргументы, метод arity возвращает отрицательное число формы -n-1. Возвращаемое значение этой формы указывает, что Proc требует n аргументов, но необязательно может принимать дополнительные аргументы также. -n-1 известен как дополнение к n, и вы можете инвертируйте его с помощью оператора ~. Поэтому, если arity возвращает отрицательное число m, то ~ m (или -m-1) дает вам количество необходимых аргументов:

lambda {|*args|}.arity # => -1. ~-1 = -(-1)-1 = 0 arguments required
lambda {|first, *rest|}.arity # => -2. ~-2 = -(-2)-1 = 1 argument required

Существует одна окончательная морщина метода arity. В Ruby 1.8, Proc объявлен без всякой аргументации (т.е. без каких-либо || символы) могут быть вызваны с любым количеством аргументов (и эти аргументы игнорируются). Метод arity возвращает -1, чтобы указать, что нет необходимых аргументов. Это изменилось в Ruby 1.9: a Proc объявленный как это имеет arity 0. Если это лямбда, то это error, чтобы вызвать его с любыми аргументами:

puts lambda {}.arity # –1 in Ruby 1.8; 0 in Ruby 1.9

Изменить 2: Стефан добавляет точную причину, по которой они отличаются в комментарии:

http://www.ruby-doc.org/core-2.0/Proc.html#method-i-call

Для procs, созданного с помощью lambda или ->(), возникает ошибка, если неправильное количество параметров передается в Proc с несколькими параметрами. Для procs, созданного с помощью Proc.new или Kernel.proc, дополнительные параметры молча отбрасываются.

Ответ 2

Как упоминалось здесь:(Различия между Proc и Lambda), одно из основных различий между procs и lambda заключается в том, что "Подобно методам, lambdas имеет строгую проверку аргументов, в то время как не-лямбда-Procs имеют свободную проверку аргументов, подобно блокам."

Таким образом, поскольку arity основан на количестве требуемых аргументов, это изменится между procs и lambdas.

Ответ 3

Прочитав другие 2 ответа, я предполагаю, что метод #arity - это толкание тонкого льда. Для фиксированного числа упорядоченных аргументов #arity используется как метод OK. Затем, когда добавлены дополнительные аргументы, чтобы придерживаться представления arity одним целым числом, знак минус использовался как флаг. Но уже, информация поля аргумента отбрасывается, как, например. 1ary или 2ary -> a, b=1 { a + b } указывает ту же самую arity (-2) как -> a, *b { a + b.sum }, беря 1 на произвольное количество аргументов. После изменения поведения #arity в 1.9, другой удар приходит в 2.0, где вводятся именованные аргументы, которые полностью игнорируются #arity. Опять же, будут обязательные и необязательные именованные аргументы, плюс возможность сбора произвольного числа из них с хэш-всплеском **. Я бы ожидал, что метод #arity снова изменит свое поведение в будущем...