Recursion in yield - ruby

So i am trying to do something like this:
def func(x,y)
if x.length == 1 then
n = x.pop()
yield(n,y)
else
n = x.pop()
yield(n,func(x,y))
end
end
calling it like:
a = func([1,2,3,4,5],0) do |x,y|
x+y
end
Is it possible to do something like this? I keep getting no block given (yield) (LocalJumpError).
I even tried doing something a little different:
def func(x,y)
func(x,y) do |tail|
..
end
end
but no luck
Thanks.

Yes, you can take the block as an argument explicitly:
def func(x, y, &block)
You can still yield to it with the yield keyword, but you can also pass it as you recurse:
yield(n, func(x, y, &block))
The & in both cases means that the block argument is not a normal argument, but represents the block that can be attached to any Ruby method call.

You are missing to pass the block in the recursive call.
The recursive call should be like as below:-
yield(n,func(x,y)) { |x,y| x+y})
Since you missed to pass the block in the recursive call, when the code hits:-
if x.length == 1 then
n = x.pop()
yield(n,y) <<<< Here
the method func doesn't have block passed as argument,in the recursive call, but ruby tries to call a non-existent block and hence the error.

Related

Why does this block not run when it is stored in a proc?

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]!'

Yield within Set to eliminate in an Array

I found the following code here for eliminating duplicate records in an array:
require 'set'
class Array
def uniq_by
seen = Set.new
select{ |x| seen.add?( yield( x ) ) }
end
end
And we can use the code above as follows:
#messages = Messages.all.uniq_by { |h| h.body }
I would like to know how and what happens when the method is called. Can someone explain the internals of the code above? In the uniq_by method, we did not do anything to handle block argument. How is the passed argument handled by uniq_by method?
Let's break it down :
seen = Set.new
Create an empty set
select{ |x| seen.add?( yield( x ) ) }
Array#select will keep elements when the block yields true.
seen.add?(yield(x)) will return true if the result of the block can be added in the set, or false if it can't.
Indeed, yield(x) will call the block passed to the uniq_by method, and pass x as an argument.
In our case, since our block is { |h| h.body }, it would be the same as calling seen.add?(x.body)
Since a set is unique, calling add? when the element already exists will return false.
So it will try to call .body on each element of the array and add it in a set, keeping elements where the adding was possible.
The method uniq_by accepts a block argument. This allows to specify, by what criteria you wish to identify two elements as "unique".
The yield statement will evaluate the value of the given block for the element and return the value of the elements body attribute.
So, if you call unique_by like above, you are stating that the attribute body of the elements has to be unique for the element to be unique.
To answer the more specific question you have: yield will call the passed block {|h| h.body} like a method, substituting h for the current x and therefore return x.body
In Ruby, when you are putting yield keyword inside any method(say #bar), you are explicitly telling #bar that, you will be using a block with the method #bar. So yield knows, inside the method block will be converted to a Proc object, and yield have to call that Proc object.
Example :
def bar
yield
end
p bar { "hello" } # "hello"
p bar # bar': no block given (yield) (LocalJumpError)
In the uniq_by method, we did not do anything to handle block argument. How is the passed argument handled by uniq_by method?
You did do, that is you put yield. Once you will put this yield, now method is very smart to know, what it supposed to so. In the line Messages.all.uniq_by { |h| h.body } you are passing a block { |h| h.body }, and inside the method definition of uniq_by, that block has been converted to a Proc object, and yield does Proc#call.
Proof:
def bar
p block_given? # true
yield
end
bar { "hello" } # "hello"
Better for understanding :
class Array
def uniq_by
seen = Set.new
select{ |x| seen.add?( yield( x ) ) }
end
end
is same as
class Array
def uniq_by
seen = Set.new
# Below you are telling uniq_by, you will be using a block with it
# by using `yield`.
select{ |x| var = yield(x); seen.add?(var) }
end
end
Read the doc of yield
Called from inside a method body, yields control to the code block (if any) supplied as part of the method call. If no code block has been supplied, calling yield raises an exception. yield can take an argument; any values thus yielded are bound to the block's parameters. The value of a call to yield is the value of the executed code block.
Array#select returns a new array containing all elements of the array for which the given block returns a true value.
The block argument of the select use Set#add? to determine whether the element is already there. add? returns nil if there is already the same element in the set, otherwise it returns the set itself and add the element to the set.
The block again pass the argument (an element of the array) to another block (the block passed to the uniq_by) using yield; Return value of the yield is return value of the block ({|h| h.body })
The select .. statement is basically similar to following statement:
select{ |x| seen.add?(x.body) }
But by using yield, the code avoid hard-coding of .body, and defers decision to the block.

Creating a Matrix class in ruby. The [] method

I've been assigned to create a new matrix class. I cannot use the require 'Matrix'.
I have this to access the element of the matrix, where #matrix is an array of arrays.
def [] (i, j)
#matrix[i][j]
end
if i try to access it like this:
#a[0][0]
it wont work. (wrong number of arguments)
but if i do it like this:
#a.[](0,0)
or
#a[0,0]
it works just fine.
Any ideas on how to make it work?
def [] (i, j)
#matrix[i][j]
end
According to the method [] it needs 2 arguments. But #a[0][0] doesn't do that,as here you are passing the method [] only 1 argument,ie.e 0. only. So you got the error. But #a.[](0,0) or #a[0,0] are perfect,as you are sending 2 arguments to the method []. When you write #a[0,0],then Ruby internally does the method call as #a.[](0,0).
how would you modify the code so #a[0][0] works?
Here is a code example:
class Matrix
def initialize(a)
#matrix=a
end
def [](*a)
a.size == 1 ? #matrix[*a] : #matrix[a.first][a.last]
end
end
a = [[1,2,3],[4,7,5],[11,21,33]]
m = Matrix.new(a)
p m[2,2] # => 33
You need to write a method that either calls it self recursively or checks how many arguments that are passed to the function. It is hard to say if this works as I do not have you entire class, but something like this might work:
def [] (*cords)
return #matrix[*cords] if cords.size == 1
#matrix[cords.first][cords.last]
end
Or a recursive version that works for any number dimensions:
def [] (*cords)
cords.inject(#matrix){|m, c| m[c]}
end
def [](i)
#matrix[i]
end
would do it, I guess. FWIW, Ruby's Matrix has [] implemented same as you: [](i,j)

Ruby yield example explanation?

I'm doing a SaaS course with Ruby. On an exercise, I'm asked to calculate the cartesian product of two sequences by using iterators, blocks and yield.
I ended up with this, by pure guess-and-error, and it seems to work. But I'm not sure about how. I seem to understand the basic blocks and yield usage, but this? Not at all.
class CartProd
include Enumerable
def initialize(a,b)
#a = a
#b = b
end
def each
#a.each{|ae|
#b.each{|be|
yield [ae,be]
}
}
end
end
Some explanation for a noob like me, please?
(PS: I changed the required class name to CartProd so people doing the course can't find the response by googling it so easily)
Let's build this up step-by-step. We will simplify things a bit by taking it out of the class context.
For this example it is intuitive to think of an iterator as being a more-powerful replacement for a traditional for-loop.
So first here's a for-loop version:
seq1 = (0..2)
seq2 = (0..2)
for x in seq1
for y in seq2
p [x,y] # shorthand for puts [x, y].inspect
end
end
Now let's replace that with more Ruby-idiomatic iterator style, explicitly supplying blocks to be executed (i.e., the do...end blocks):
seq1.each do |x|
seq2.each do |y|
p [x,y]
end
end
So far, so good, you've printed out your cartesian product. Now your assignment asks you to use yield as well. The point of yield is to "yield execution", i.e., pass control to another block of code temporarily (optionally passing one or more arguments).
So, although it's not really necessary for this toy example, instead of directly printing the value like above, you can yield the value, and let the caller supply a block that accepts that value and prints it instead.
That could look like this:
def prod(seq1, seq2)
seq1.each do |x|
seq2.each do |y|
yield [x,y]
end
end
end
Callable like this:
prod (1..2), (1..2) do |prod| p prod end
The yield supplies the product for each run of the inner loop, and the yielded value is printed by the block supplied by the caller.
What exactly do you not understand here? You've made an iterator that yields all possible pairs of elements. If you pass CartProd#each a block, it will be executed a.length*b.length times. It's like having two different for cycles folded one into another in any other programming language.
yield simply passes (yields) control to a block of code that has been passed in as part of the method call. The values after the yield keyword are passed into the block as arguments. Once the block has finished execution it passes back control.
So, in your example you could call #each like this:
CartProd.new([1, 2], [3, 4]).each do |pair|
# control is yielded to this block
p pair
# control is returned at end of block
end
This would output each pair of values.

Understanding Ruby Enumerable#map (with more complex blocks)

Let's say I have a function
def odd_or_even n
if n%2 == 0
return :even
else
return :odd
end
end
And I had a simple enumerable array
simple = [1,2,3,4,5]
And I ran it through map, with my function, using a do-end block:
simple.map do
|n| odd_or_even(n)
end
# => [:odd,:even,:odd,:even,:odd]
How could I do this without, say, defining the function in the first place? For example,
# does not work
simple.map do |n|
if n%2 == 0
return :even
else
return :odd
end
end
# Desired result:
# => [:odd,:even,:odd,:even,:odd]
is not valid ruby, and the compiler gets mad at me for even thinking about it. But how would I implement an equivalent sort of thing, that works?
edit
In reality, the solution to my problem matters to me a lot less than the motivation/reasoning behind it, to help me understand more how ruby blocks work :)
You're so close. Just remove the returns and you're golden.
This is because the block passed to map is a proc (i.e. created with Proc.new), and not a lambda. A return within a proc doesn't just jump out of the proc- it jumps out of the method that executed (i.e. called call on) the proc. A return within a lambda, on the other hand, jumps out of only the lambda.
The proc method returns a lambda in Ruby 1.8, and a Proc in Ruby 1.9. It's probably best to just not use this method and be explicit with which construct you want to use.
I'm guessing you were either in IRB or a plain ruby script when you were trying this out.
a = Proc.new { return }
a.call # fails. Nothing to return from.
def foobar
a = Proc.new { return }
a.call
puts 'hello' # not reached. The return within the proc causes execution to jump out of the foobar method.
end
foobar # succeeds, but does not print 'hello'. The return within the proc jumps out of the foobar method.
b = lambda { return }
b.call # succeeds. The return only returns from the lambda itself.
def bazquux
b = lambda { return }
b.call
puts 'hello' # this is reached. The lambda only returned from itself.
end
bazquux # succeeds, and prints 'hello'
The lesson to learn from this is to use implicit returns unless you can't, I guess.
I suspect this may be a duplicate question, but to give a value out of a block, use next
simple.map do |n|
if n%2 == 0
next :even
else
next :odd
end
end
Shortest variant using Andrew's answer:
simple.map { |n| next :even if n % 2 == 0; :odd }

Resources