Ruby lambda arguments - ruby

This code works as expected (does nothing, even doesn't produce warning/errors):
l = lambda {|i|}
l.call(1)
This code produces warning (warning: multiple values for a block parameter (0 for 1)):
l = lambda {|i|}
l.call
And this code fails with error (ArgumentError: wrong number of arguments (0 for 2)):
l = lambda {|i, y|}
l.call
I thought that lambda requires all argument to be passed.
And from the second example I see that it isn't. Why does it work when only one argument is given, and works as expected (fails with error) with more than one argument?
PS: ruby 1.8.6 (2008-08-11 patchlevel 287) [universal-darwin9.0]
UPDATE: I've checked these samples with ruby 1.9.1p376. And it works as expected - the second example also produces an error. Looks like this is a feature of 1.8 version (or <=1.8)

Lambdas are weird like that, their behavior is different when you have less than two arguments. Check this article for more information.

This script will teach you everything you need to know about closures in Ruby.
# So, what's the final verdict on those 7 closure-like entities?
#
# "return" returns from closure
# True closure? or declaring context...? Arity check?
# --------------- ----------------------------- -------------------
# 1. block (called with yield) N declaring no
# 2. block (&b => f(&b) => yield) N declaring no
# 3. block (&b => b.call) Y except return declaring warn on too few
# 4. Proc.new Y except return declaring warn on too few
# 5. proc <<< alias for lambda in 1.8, Proc.new in 1.9 >>>
# 6. lambda Y closure yes, except arity 1
# 7. method Y closure yes

When a lambda expects arguments and we don't provide them, or we provide the wrong number of arguments, an exception is thrown.
l = lambda { |name| puts "Today we will practice #{name} meditation." }
l.call
ArgumentError: wrong number of arguments (given 0, expected 1)
We can use the arity method to find out the number of expected arguments:
l.arity # Output: => 1
Just like methods, lambdas accept all of the following types of parameters/arguments:
Positional parameters (required and optional)
Single splat parameter (*);
Keyword parameters (required and optional);
Double splat parameter (**);
Explicit block parameter prefixed with ampersand (&).
The following examples illustrate the syntax of a lambda that takes multiple types of arguments.
# Stabby syntax
l = -> (cushion, meditation="kinhin", *room_items, time:, posture: "kekkafuza", **periods, &p) do
p.call
end
# Regular syntax
l = lambda do |cushion, meditation="kinhin", *room_items, time:, posture: "kekkafuza", **periods, &p|
p.call
end
l.call("zafu", "zazen", "zabuton", "incense", time: 40, period1: "morning", period2: "afternoon" ) { puts "Hello from inside the block, which is now a proc." }
Output:
Hello from inside the block, which is now a proc.
Lambdas handle arguments the same way as methods. There is a comprehensive explanation of all the above parameter/argument types in this blog post about methods.

Related

Why is `to_ary` called from a double-splatted parameter in a code block?

It seems that a double-splatted block parameter calls to_ary on an object that is passed, which does not happen with lambda parameters and method parameters. This was confirmed as follows.
First, I prepared an object obj on which a method to_ary is defined, which returns something other than an array (i.e., a string).
obj = Object.new
def obj.to_ary; "baz" end
Then, I passed this obj to various constructions that have a double splatted parameter:
instance_exec(obj){|**foo|}
# >> TypeError: can't convert Object to Array (Object#to_ary gives String)
->(**foo){}.call(obj)
# >> ArgumentError: wrong number of arguments (given 1, expected 0)
def bar(**foo); end; bar(obj)
# >> ArgumentError: wrong number of arguments (given 1, expected 0)
As can be observed above, only code block tries to convert obj to an array by calling a (potential) to_ary method.
Why does a double-splatted parameter for a code block behave differently from those for a lambda expression or a method definition?
I don't have full answers to your questions, but I'll share what I've found out.
Short version
Procs allow to be called with number of arguments different than defined in the signature. If the argument list doesn't match the definition, #to_ary is called to make implicit conversion. Lambdas and methods require number of args matching their signature. No conversions are performed and that's why #to_ary is not called.
Long version
What you describe is a difference between handling params by lambdas (and methods) and procs (and blocks). Take a look at this example:
obj = Object.new
def obj.to_ary; "baz" end
lambda{|**foo| print foo}.call(obj)
# >> ArgumentError: wrong number of arguments (given 1, expected 0)
proc{|**foo| print foo}.call(obj)
# >> TypeError: can't convert Object to Array (Object#to_ary gives String)
Proc doesn't require the same number of args as it defines, and #to_ary is called (as you probably know):
For procs created using lambda or ->(), an error is generated if wrong number of parameters are passed to the proc. For procs created using Proc.new or Kernel.proc, extra parameters are silently discarded and missing parameters are set to nil. (Docs)
What is more, Proc adjusts passed arguments to fit the signature:
proc{|head, *tail| print head; print tail}.call([1,2,3])
# >> 1[2, 3]=> nil
Sources: makandra, SO question.
#to_ary is used for this adjustment (and it's reasonable, as #to_ary is for implicit conversions):
obj2 = Class.new{def to_ary; [1,2,3]; end}.new
proc{|head, *tail| print head; print tail}.call(obj2)
# >> 1[2, 3]=> nil
It's described in detail in a ruby tracker.
You can see that [1,2,3] was split to head=1 and tail=[2,3]. It's the same behaviour as in multi assignment:
head, *tail = [1, 2, 3]
# => [1, 2, 3]
tail
# => [2, 3]
As you have noticed, #to_ary is also called when when a proc has double-splatted keyword args:
proc{|head, **tail| print head; print tail}.call(obj2)
# >> 1{}=> nil
proc{|**tail| print tail}.call(obj2)
# >> {}=> nil
In the first case, an array of [1, 2, 3] returned by obj2.to_ary was split to head=1 and empty tail, as **tail wasn't able to match an array of[2, 3].
Lambdas and methods don't have this behaviour. They require strict number of params. There is no implicit conversion, so #to_ary is not called.
I think that this difference is implemented in these two lines of the Ruby soruce:
opt_pc = vm_yield_setup_args(ec, iseq, argc, sp, passed_block_handler,
(is_lambda ? arg_setup_method : arg_setup_block));
and in this function. I guess #to_ary is called somewhere in vm_callee_setup_block_arg_arg0_splat, most probably in RARRAY_AREF. I would love to read a commentary of this code to understand what happens inside.

Why do you have to specify 2 arguments explicitly to curry :>

Consider this, which works fine:
:>.to_proc.curry(2)[9][8] #=> true, because 9 > 8
However, even though > is a binary operator, the above won't work without the arity specified:
:>.to_proc.curry[9][8] #=> ArgumentError: wrong number of arguments (0 for 1)
Why aren't the two equivalent?
Note: I specifically want to create the intermediate curried function with one arg supplied, and then call then call that with the 2nd arg.
curry has to know the arity of the proc passed in, right?
:<.to_proc.arity # => -1
Negative values from arity are confusing, but basically mean 'variable number of arguments' one way or another.
Compare to:
less_than = lambda {|a, b| a < b}
less_than.arity # => 2
When you create a lambda saying it takes two arguments, it knows it takes two arguments, and will work fine with that style of calling #curry.
less_than.curry[9][8] # => false, no problem!
But when you use the symbol #to_proc trick, it's just got a symbol to go on, it has no idea how many arguments it takes. While I don't think < is actually an ordinary method in ruby, I think you're right it neccessarily takes two args, the Symbol#to_proc thing is a general purpose method that works on any method name, it has no idea how many args the method should take, so defines the proc with variable arguments.
I don't read C well enough to follow the MRI implementation, but I assume Symbol#to_proc defines a proc with variable arguments. The more typical use of Symbol#to_proc, of course, is for a no-argument methods. You can for instance do this with it if you want:
hello_proc = :hello.to_proc
class SomeClass
def hello(name = nil)
puts "Hello, #{name}!"
end
end
obj = SomeClass.new
obj.hello #=> "Hello, !"
obj.hello("jrochkind") #=> "Hello, jrochkind!"
obj.hello("jrochkind", "another")
# => ArgumentError: wrong number of arguments calling `hello` (2 for 1)
hello_proc.call(obj) # => "Hello, !"
hello_proc.call(obj, "jrochkind") # => "Hello, jrochkind!"
hello_proc.call(obj, "jrochkind", "another")
# => ArgumentError: wrong number of arguments calling `hello` (2 for 1)
hello_proc.call("Some string")
# => NoMethodError: undefined method `hello' for "Some string":String
Note I did hello_proc = :hello.to_proc before I even defined SomeClass. The Symbol#to_proc mechanism creates a variable arity proc, that knows nothing about how or where or on what class it will be called, it creates a proc that can be called on any class at all, and can be used with any number of arguments.
If it were defined in ruby instead of C, it would look something like this:
class Symbol
def to_proc
method_name = self
proc {|receiver, *other_args| receiver.send(method_name, *other_args) }
end
end
I think it is because Symbol#to_proc creates a proc with one argument. When turned into a proc, :> does not look like:
->x, y{...}
but it looks like:
->x{...}
with the requirement of the original single argument of > somehow tucked inside the proc body (notice that > is not a method that takes two arguments, it is a method called on one receiver with one argument). In fact,
:>.to_proc.arity # => -1
->x, y{}.arity # => 2
which means that applying curry to it without argument would only have a trivial effect; it takes a proc with one parameter, and returns itself. By explicitly specifying 2, it does something non-trivial. For comparison, consider join:
:join.to_proc.arity # => -1
:join.to_proc.call(["x", "y"]) # => "xy"
:join.to_proc.curry.call(["x", "y"]) # => "xy"
Notice that providing a single argument after Currying :join already evaluates the whole method.
#jrochkind's answer does a great job of explaining why :>.to_proc.curry doesn't have the behavior you want. I wanted to mention, though, that there's a solution to this part of your question:
I specifically want to create the intermediate curried function with one arg supplied, and then call then call that with the 2nd arg.
The solution is Object#method. Instead of this:
nine_is_greater_than = :>.to_proc.curry[9]
nine_is_greater_than[8]
#=> ArgumentError: wrong number of arguments (0 for 1)
...do this:
nine_is_greater_than = 9.method(:>)
nine_is_greater_than[8]
# => true
Object#method returns a Method object, which acts just like a Proc: it responds to call, [], and even (as of Ruby 2.2) curry. However, if you need a real proc (or want to use curry with Ruby < 2.2) you can also call to_proc on it (or use &, the to_proc operator):
[ 1, 4, 8, 10, 20, 30 ].map(&nine_is_greater_than)
# => [ true, true, true, false, false, false ]

Ruby: specifying value of single argument on multiple argument function with default values

Coming from a python background, I'm used to running functions providing only the parameters that I need:
def f(a=1,b=2)
print a,b
f(b=3) #prints "1 3"
Ruby seems to provide the same syntax for optional parameters:
def f(a=1, b=2)
puts "#{a} #{b}"
end
But running f(b=3) prints 3 2 instead.
My guess is that it's evaluating b=3 before the function call occurs, and passing it as the first argument.
Is this interpretation correct, and is there a way to call a function providing arbitrary arguments?
f(b=3) means a local variable b create with value assignment as 3, then it passed as an argument. Son in your method actual parameter a got value 3, and b goes with its default value 2.
Thus running f(b=3) prints 3 2 instead.
In Ruby when you are calling a method, you are just passing the values to the methods actual argument, no scope to set the value of its actual parameters from method calling area.
You should use Keyword Arguments to meet your need. I wouldn't write the code, as #sawa did it for you.
Notice that all arguments are evaluated prior to a method call. If you do f(b = 3), then value assignment b = 3 takes place first, whose return value is 3, and that is used as the argument, so it is the same as doing f(3). Since you provide only one argument, it will be interpreted as the first argument a, and the default value would be used for b.
You are using the wrong construction. This is the way to do it:
def f a: 1, b: 2
puts "#{a} #{b}"
end
f(b: 3)
# => 1 3
It is using keyword arguments introduced in Ruby 2.0, as is explained in a page that Arup's answer links to.
Here is a workaround for Ruby 1.8, Ruby 1.9.
def f h = {}
h[:a] ||= 1
h[:b] ||= 2
puts "#{h[:a]} #{h[:b]}"
end
f(:b => 3) # Ruby 1.8
f(b: 3) # Ruby 1.9
# => 1 3

Ruby and Lambda calculus

I'm trying to understand lambda calculus with procs and ruby. Here is some code:
puts -> x { -> y {x.call(y) } }
# => #<Proc:0x2a3beb0#C:/first-ruby.rb:1 (lambda)>
puts -> x { x + 2}.call(1)
# => 3
What does -> signify in above example? Is the call method passing the value to the caller, so in the first example, value y is passed to y and in the second example, 1 is passed to x? In the second example, why is 1 evaluated to x?
This is a shortcut for the pure lambda expression:
lmbd = -> arg{ something to do with arg } # With ->{} notation
lmbd = lambda { |arg| something to do with arg } # Standard notation
In your first example you invoke puts method with Proc(lambda) object, and that's why you see #<Proc:0x2a3beb0#C:/first-ruby.rb:1 (lambda)> in the output.
In the second example you invoke puts with lmbd.call(1) method, i.e. puts outputs the result of lambda calculation.
So, if you have lmbd variable which is lambda object, you can pass it like any argument and then get it's result by invoke lmbd.call():
lmbd = -> greeting{ puts "#{greeting}, lambda-expression!" }
def say_hello l, text
l.call(text)
end
say_hello lmbd, "Aloha" # => Aloha, lambda-expression!
What does -> signify in above example?
-> is part of the literal syntax for lambdas, just like, say, ' is part of the literal syntax for strings.
Is the .call method just passing the value from to caller,
The call method is the method, which, well, calls (or executes) the lambda. The arguments to the call method are bound to the parameters of the lambda.
so in first example value y is passed to y and in second example 1 is passed to x.
No, in the first example, y is passed to the outer lambda and bound to its x parameter. In the second example, 1 is passed to the lambda and bound to its x parameter.
In second example why how is 1 evaluated to x?
1 does not evalute to x. 1 is an immediate value, and in Ruby, immediate values always evaluate to themselves. 1 will always evaluate to 1, never to x or anything else.
Let's define a function using Ruby lambda.
def plus_two # no args here
->(x) {x + 2} # args go here
end
# assign a value
x = 1
# call it
plus_two.call(x)
# => 3
Your first example is a bit more complex but using this idea you should be able to come up with functional methods.
I'm studying Scala and functional programming is based upon these substitution principles.
Try doing some recursion using these.
It's like calling functions of functions n times.
What would be the base case then?
As for the Lambda Calculus https://github.com/mackorone/lambda/blob/master/intro.pdf
Try to keep things simple and show the steps rather than trying to figure out what a one liner is doing. Yes they are nice but if you can't read it you can't understand it.
Here's something I was just recently working on:
require 'date'
num = DateTime.now.to_time.utc.to_datetime.ajd - 2451545.0
#t = num / 36525.0
# the terms in reverse order form for the array
#l0_a = [1.0/-19880000.0,
1.0/-152990.0,
1.0/499310.0,
0.0003032028,
36000.76982779,
280.4664567]
# make an enumerator
#l0_e = #l0_a.each
# make a lambda to pass the enumerator to.
def my_lambda
->(x) {x.reduce {|acc, el| acc * #t + el} % 360}
end
puts my_lambda.call(#l0_e)
This is mean longitude of the sun formula using enumerator methods and of course a lambda.

Simple Currying in Ruby

I'm trying to do some currying in ruby:
def add(a,b)
return a+b
end
plus = lambda {add}
curry_plus = plus.curry
plus_two = curry_plus[2] #Line 24
puts plus_two[3]
I get the error
func_test.rb:24:in `[]': wrong number of arguments (1 for 0) (ArgumentError)
from func_test.rb:24:in `'
But if I do
plus = lambda {|a,b| a+ b}
It seems to work. But by printing plus after the assigning with lambda both ways return the same type of object. What have I misunderstood?
You're on the right track:
add = ->(a, b) { a + b }
plus_two = add.curry[2]
plus_two[4]
#> 6
plus_two[5]
#> 7
As others have pointed out, the plus lambda you defined doesn't take any arguments and calls the add method with no arguments.
lambda {|a,b| a+ b}
Creates a lambda which takes two arguments and returns the result of calling + on the first, with the second as its arguments.
lambda {add}
Creates a lambda which takes no arguments and calls add without arguments, which is an error of course.
To do what you want, you should do
plus = lambda {|x,y| add(x,y)}
or
plus = method(:add).to_proc
When you write lambda {add}, you're declaring a Proc that takes no arguments and, as its sole action, calls add with no arguments. It doesn't turn add into a Proc. On the other hand, lambda {|a,b| a + b} returns a Proc that takes two arguments and adds them together — since it takes arguments, it's valid to pass arguments to that one.
I think what you want is method(:add).to_proc.curry.

Resources