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.
Related
I'm trying to create a Ruby method that:
1. accepts as input a proc which accepts two arguments and
2. returns as output a proc which takes one argument (the other argument being passed in with the first proc.)
Code below. Everything I've read about how Ruby handles functional scope indicates that I should be able to return a proc.call as a variable, and I don't understand why I'm getting an "unexpected return" error (reproduced below the code)
(I'm obviously a beginning Rubyist...my experience has mostly been in JavaScript, where the mechanics of doing this sort of thing are, I think, much more intuitive.)
--
def partial (proc1, val1)
return Proc.new {|val2| return proc1.call(val1,val2)}
end
adder = Proc.new {|a,b| a + b}
sum_five = partial(adder,5)
sum_five.call(10) # -- expecting 15
# unexpected return
# (repl):13:in `block in partial'
# (repl):20:in `<main>'
In Ruby, procs and lambdas treat return differently.
Procs are designed to work within other Ruby control structures, so in that context a return is from the control structure. Lambdas are much more like stand-alone methods, so return returns from the lambda. You get an error because the proc has no context to return from.
Try this:
def partial (proc1, val1)
return lambda {|val2| return proc1.call(val1,val2)}
end
adder = Proc.new {|a,b| a + b}
sum_five = partial(adder,5)
puts sum_five.call(10) # -- expecting 15
Shorter/cleaner ruby syntax:
def composer(proc1, val1)
-> (val2) { proc1.call(val1, val2) }
end
adder = -> (a,b) { a + b }
sum_five = composer(adder, 5)
sum_five.call(10)
Although I don't understand it's name, Ruby already has a method, Proc#curry, that does this:
adder = Proc.new {|a,b| a + b}
sum_five = adder.curry.call(5)
sum_five.call(10) # => 15
sum_five.call(2) # => 7
just watch out, because curry takes an optional argument, which is the number of arguments it should expect before calling the initial proc, so if you pass it the argument you want as the "default" it'll work weird:
adder = Proc.new {|a,b| a + b}
sum_five = adder.curry(5) # NOTE: This is incorrect
sum_five.call(1) # => returns a Proc
sum_five[1][2][3][4][5] # => 3 (the first 2 arguments got passed, the rest ignored)
I'm learning ruby and trying to get a better understanding of Blocks, Yield, Procs and Methods and I stumbled upon this example on using yield.
def calculation(a, b)
yield(a, b)
end
x = calculation(5,6) do|a,b|
a + b
end
puts "#{x}"
From what I understand Procs are object that holds a pointer to Blocks. And Blocks need a method to work in the first place. Also, from the way yield is used, I assume yield jumps to the block immediately after the method call.
I assume the code runs this way: calculation(5,6) calls the method calculation(). when the yield instruction executes, a and b are passed to the block after calculation(5,6). To experement and get a better understand I tried doing this.
def calculation(a, b)
yield(a, b)
end
ankh = Proc.new do |a,b|
a + b
end
x = calculation(5,6) *ankh
The error says that no block is given to calculation(). But aren't we giving calculation(5,6) the block ankh? Hopefully my question isn't too confusing.
You have a syntax error in the line x = calculation(5,6) *ankh. To pass a method as a block, you use the &-operator.
x = calculation(5,6,&ankh)
First off: what you wrote doesn't make any sense. Think about it: what does
calculation(5, 6) * ankh
mean? Or, more abstractly, what does
foo * bar
mean? Does 2 * 3 really mean "call 2 and pass 3 as a block"?
The error says that no block is given to calculation(). But aren't we giving calculation(5,6) the block ankh?
No, ankh is not a block, it's a Proc. A block is a purely syntactic construct. Most importantly, a block is not an object, so you simply cannot store it in a variable at all. You also cannot pass it as a normal argument to a method, you have to pass it as a separate "special" block argument. Blocks do not exist independent from method calls.
There is, however, a way of "converting" a Proc into a block: the & ampersand unary prefix operator:
x = calculation(5, 6, &ankh)
# => 11
This tells Ruby to take the Proc ankh and turn it into a block. In fact, this mechanism is much more general than that, because you can even pass an object which is not a Proc and Ruby will first call to_proc on that object to allow it to convert itself to a Proc.
For example, Method implements to_proc, so you can pass Methods as blocks:
def ankh(a, b) a + b end
x = calculation(5, 6, &method(:ankh))
# => 11
Also, Symbol implements to_proc:
x = calculation(5, 6, &:+)
# => 11
Lastly, Hash implements to_proc as well.
And, of course, you can write your own objects that implement to_proc:
def (ankh = Object.new).to_proc
-> *args { "I was called with arguments #{args.inspect}!" }
end
x = calculation(5, 6, &ankh)
# => 'I was called with arguments [5, 6]!'
My got an error message "method_object.rb:8:in `': wrong argument type Fixnum (expected Proc) (TypeError)" when trying to run the following script
def f(x,y=2)
x**y
end
a=method(:f).to_proc
b=a.curry.curry[4]
print 1.upto(5).map(&b)
puts
However, if function f is defined in the following way, everything was OK.
def f(x,y)
x**y
end
Would any one help me with what went wrong with my first code?
Proc#curry
Returns a curried proc. If the optional arity argument is given, it determines the number of arguments. A curried proc receives some arguments. If a sufficient number of arguments are supplied, it passes the supplied arguments to the original proc and returns the result. Otherwise, returns another curried proc that takes the rest of arguments.
Now coming to your code :
def f(x, y=2)
x**y
end
a = method(:f).to_proc
b = a.curry.curry[4]
b.class # => Fixnum
b # => 16
print 1.upto(5).map(&b)
# wrong argument type Fixnum (expected Proc) (TypeError)
Look the documentation now - A curried proc receives some arguments. If a s*ufficient number* of arguments are supplied, it passes the supplied arguments to the original proc and returns the result.
In your code, when you did a.curry, it returns a curried proc. Why? Because your method f has one optional and one required argument, but you didn't provide any. Now you call again a.curry.curry[4], so on the previous curried proc which is still waiting for at-least one argument, this time you gave to it by using curry[4]. Now curried proc object gets called with 4, 2 as arguments, and evaluated to a Fixnum object 8 and assigned to b. b is not a proc object, rather a Fixnum object.
Now, 1.upto(5).map(&b) here - &b means, you are telling convert the proc object assgined to b to a block. But NO, b is not holding proc object, rather Fixnum object 8. So Ruby complains to you.
Here the message comes as wrong argument type Fixnum (expected Proc) (TypeError).
Now coming to your second part of code. Hold on!! :-)
Look below :
def f(x, y)
x**y
end
a = method(:f).to_proc
b = a.curry.curry[4]
b.class # => Proc
b # => #<Proc:0x87fbb6c (lambda)>
print 1.upto(5).map(&b)
# >> [4, 16, 64, 256, 1024]
Now, your method f needs 2 mandatory argument x, y. a.curry, nothing you passed so a curried proc is returned. Again a.curry.curry[4], humm you passed one required argument, which is 4 out of 2. So again a curried proc returned.
Now 1.upto(5).map(&b), same as previous b expects a proc, and you fulfilled its need, as now b is proc object. &b converting it to a block as below :
1.upto(5).map { |num| b.call(num) }
which in turn outputs as - [4, 16, 64, 256, 1024].
Summary
Now suppose you defined a proc as below :
p = Proc.new { |x, y, z = 2| x + y + z }
Now you want to make p as curried proc. So you did p.curry. Remember you didn't pass any arity when called curry. Now point is a curried proc will wait to evaluate and return the result of x + y + z, unless and until, you are giving it all the required arguments it needs to produce it results.
That means p.curry gives you a curried proc object, then if you do p.curry[1] ( mean you are now passing value to x ), again you got a curried proc. Now when you will write p.curry[1][2], all required arguments you passed ( mean you are now passing value to y ), so now x + y + z will be called.
You are using .map, it requires a block of type proc. In your first case b returns 16 as y=2 uses default value 2 for exponent when you are sending single argument using curry. b returning 16 is not a proc object and can not be used with .map.
Curry when used with a proc with sufficient arguments, it executes original proc and returns a result. Which is happening in OP's first case with curried proc passed with 4 as only argument and default y=2 in f(x, y=2) getting used and resulting in 16 as return value. 16 being Fixnum can not be used with enumerator map method.
Curry when used with insufficient arguments return a proc. So in case 2 when f(x, y) is used curried a is passed only single argument resulting in a proc object {|e| 4 ** e} being returned and which gets executed by map method.
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
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.