Enumerator new and yield - ruby

At ruby docs I found this piece of code:
fib = Enumerator.new do |y|
a = b = 1
loop do
y << a
a, b = b, a + b
end
end
Thing is i cant understand what it does. In general it calculates fibonacci's numbers, but I have hard time understanding the details. What is y (Enumerator::Yielder)? The docs says nothing about it. What does << method do? (I know its yield alias). Why does infinite loop happen when y << a
is removed?Thanks!

Consider the following code:
fib = Enumerator.new do |y|
puts "Enter enumerator"
a = b = 1
loop do
puts "Inside loop"
y << a
puts "y: #{y.inspect}, a: #{a}, b: #{b}"
a, b = b, a + b
end
end
puts fib.take(5)
It prints:
# Enter enumerator
# Inside loop
# y: #<Enumerator::Yielder:0x000000059a27e8>, a: 1, b: 1
# Inside loop
# y: #<Enumerator::Yielder:0x000000059a27e8>, a: 1, b: 2
# Inside loop
# y: #<Enumerator::Yielder:0x000000059a27e8>, a: 2, b: 3
# Inside loop
# y: #<Enumerator::Yielder:0x000000059a27e8>, a: 3, b: 5
# Inside loop
# 1
# 1
# 2
# 3
# 5
Apparently, this output actually gives hints on all the question you’ve stated. Note, that we entered a yielder only once. Let’s dig into:
Why loop is infinite?
Because Fibonacci’s number sequence is infinite. This enumerator is intended to be used with Enumerable#take (see an example above.)
What is Enumerator::Yielder?
It is an abstraction. It’s method yield actually calls back the block of callee, passing a parameter as block parameters.
What does << method does?
Yields once. In other words, it calls back the caller code, passing it’s parameter to the caller’s block. In this particular example, it will call back each block, passing a from Yielder instance as block parameter (e as I named it there.)
Why does infinite loop happen when y << a is removed?
Because there are no yields happened. In my example, the callee will stop after yielding five (5 as parameter of take) times.

Related

Method that returns result and modulo

I am trying to write a method that asks for two 2 integers, and divides the first by the second and returns the result including the remainder.
def remainder(a,b)
return a/b
return a%b
end
puts remainder(100,6)
This puts out
16
If I use this code
def remainder(a,b)
return a%b
end
puts remainder(100,6)
This puts out
4
I don't understand how to make both the modulus value and the remainder show in puts statement.
Update
Based on Simple Lime's advice I used the following code...
def remainder(a,b)
return a.divmod(b)
end
puts remainder(100,6)
Which puts
16
4
And is functioning as I had hoped.
You can return an array from the method when you need to return multiple values:
def remainder(a, b)
[a / b, a % b]
end
puts remainder(100, 6).inspect # => [16, 4]
and then you can assign each value to a different variable, if you need:
div, mod = remainder(100, 6)
puts div # => 16
puts mod # => 4
As a side note, if you are just needing both the quotient and modulus of 2 numbers, there's already a built-in function, divmod that does this, using the technique above:
100.divmod(6) # => [16, 4]

I don't understand this method

I'm a beginner in Ruby and I don't understand what this code is doing, could you explain it to me, please?
def a(n)
s = 0
for i in 0..n-1
s += i
end
s
end
def defines a method. Methods can be used to run the same code on different values. For example, lets say you wanted to get the square of a number:
def square(n)
n * n
end
Now I can do that with different values and I don't have to repeat n * n:
square(1) # => 1
square(2) # => 4
square(3) # => 9
= is an assignment.
s = 0 basically says, behind the name s, there is now a zero.
0..n-1 - constructs a range that holds all numbers between 0 and n - 1. For example:
puts (0..3).to_a
# 0
# 1
# 2
# 3
for assigns i each consecutive value of the range. It loops through all values. So first i is 0, then 1, then ... n - 1.
s += i is a shorthand for s = s + i. In other words, increments the existing value of s by i on each iteration.
The s at the end just says that the method (remember the thing we opened with def) will give you back the value of s. In other words - the sum we accumulated so far.
There is your programming lesson in 5 minutes.
This example isn't idiomatic Ruby code even if it is syntactically valid. Ruby hardly ever uses the for construct, iterators are more flexible. This might seem strange if you come from another language background where for is the backbone of many programs.
In any case, the program breaks down to this:
# Define a method called a which takes an argument n
def a(n)
# Assign 0 to the local variable s
s = 0
# For each value i in the range 0 through n minus one...
for i in 0..n-1
# ...add that value to s.
s += i
end
# The result of this method is s, the sum of those values.
s
end
The more Ruby way of expressing this is to use times:
def a(n)
s = 0
# Repeat this block n times, and in each iteration i will represent
# a value in the range 0 to n-1 in order.
n.times do |i|
s += i
end
s
end
That's just addressing the for issue. Already the code is more readable, mind you, where it's n.times do something. The do ... end block represents a chunk of code that's used for each iteration. Ruby blocks might be a little bewildering at first but understanding them is absolutely essential to being effective in Ruby.
Taking this one step further:
def a(n)
# For each element i in the range 0 to n-1...
(0..n-1).reduce |sum, i|
# ...add i to the sum and use that as the sum in the next round.
sum + i
end
end
The reduce method is one of the simple tools in Ruby that's quite potent if used effectively. It allows you to quickly spin through lists of things and compact them down to a single value, hence the name. It's also known as inject which is just an alias for the same thing.
You can also use short-hand for this:
def a(n)
# For each element in the range 0 to n-1, combine them with +
# and return that as the result of this method.
(0..n-1).reduce(&:+)
end
Where here &:+ is shorthand for { |a,b| a + b }, just as &:x would be short for { |a,b| a.x(b) }.
As you are a beginner in Ruby, let's start from the small slices.
0..n-1 => [0, n-1]. E.g. 0..3 => 0, 1, 2, 3 => [0, 3]
for i in 0.. n-1 => this is a for loop. i traverses [0, n-1].
s += i is same as s = s + i
So. Method a(n) initializes s = 0 then in the for loop i traverse [0, n - 1] and s = s + i
At the end of this method there is an s. Ruby omits key words return. so you can see it as return s
def a(n)
s = 0
for i in 0..n-1
s += i
end
s
end
is same as
def a(n)
s = 0
for i in 0..n-1
s = s + i
end
return s
end
a(4) = 0 + 1 + 2 + 3 = 6
Hope this is helpful.
The method a(n) calculates the sums of the first n natural numbers.
Example:
when n=4, then s = 0+1+2+3 = 6
Let's go symbol by symbol!
def a(n)
This is the start of a function definition, and you're defining the function a that takes a single parameter, n - all typical software stuff. Notably, you can define a function on other things, too:
foo = "foo"
def foo.bar
"bar"
end
foo.bar() # "bar"
"foo".bar # NoMethodError
Next line:
s = 0
In this line, you're both declaring the variable s, and setting it's initial value to 0. Also typical programming stuff.
Notably, the value of the entire expression; s = 0, is the value of s after the assignment:
s = 0
r = t = s += 1 # You can think: r = (t = (s += 1) )
# r and t are now 1
Next line:
for i in 0..n-1
This is starting a loop; specifically a for ... in ... loop. This one a little harder to unpack, but the entire statement is basically: "for each integer between 0 and n-1, assign that number to i and then do something". In fact, in Ruby, another way to write this line is:
(0..n-1).each do |i|
This line and your line are exactly the same.
For single line loops, you can use { and } instead of do and end:
(0..n-1).each{|i| s += i }
This line and your for loop are exactly the same.
(0..n-1) is a range. Ranges are super fun! You can use a lot of things to make up a range, particularly, time:
(Time.now..Time.new(2017, 1, 1)) # Now, until Jan 1st in 2017
You can also change the "step size", so that instead of every integer, it's, say, every 1/10:
(0..5).step(0.1).to_a # [0.0, 0.1, 0.2, ...]
Also, you can make the range exclude the last value:
(0..5).to_a # [0, 1, 2, 3, 4, 5]
(0...5).to_a # [0, 1, 2, 3, 4]
Next line!
s += i
Usually read aloud a "plus-equals". It's literally the same as: s = s + 1. AFAIK, almost every operator in Ruby can be paired up this way:
s = 5
s -= 2 # 3
s *= 4 # 12
s /= 2 # 6
s %= 4 # 2
# etc
Final lines (we'll take these as a group):
end
s
end
The "blocks" (groups of code) that are started by def and for need to be ended, that's what you're doing here.
But also!
Everything in Ruby has a value. Every expression has a value (including assignment, as you saw with line 2), and every block of code. The default value of a block is the value of the last expression in that block.
For your function, the last expression is simply s, and so the value of the expression is the value of s, after all is said and done. This is literally the same as:
return s
end
For the loop, it's weirder - it ends up being the evaluated range.
This example may make it clearer:
n = 5
s = 0
x = for i in (0..n-1)
s += i
end
# x is (0..4)
To recap, another way to write you function is:
def a(n)
s = 0
(0..n-1).each{ |i| s = s + i }
return s
end
Questions?

Comma assignment (why right go first?) i.e. n,m = 1, 2?

In the process of figuring out blocks and yields I came across these comma-separated assignments:
def fibit
n,m =1,1
loop do |variable|
yield n
n,m = m,n+m # this line
puts "n is #{n} m is #{m}"
end
end
fibit do |num|
puts "Next : #{num}"
break if num > 100
end
Why does the m get assigned first in this scenario?
Does the last one always go first? If so why?
This was also seen as only e has the value of 1 meaning e went first?
e,r=1
puts r
puts "-------"
puts e
Also, does anyone have an idea why the code-block versions just executes, where if I write the same code with no code block I actually need to call the method for it to run?
def fibit
n,m =1,1
loop do |variable|
puts "Next : #{n}"
break if n > 100
n,m = m,n+m
end
end
fibit
If I didn't have the last line it wouldn't run. Where in the first one I don't actually call the fibit method? Or is the block kicking it off?
m does not get assigned first. When using multiple assignments, all right hand side calculations are done before any assignment to the left hand side.
That's how this code works:
a = 1
b = 3
a, b = b, a
a
# => 3
b
# => 1
This would not be possible if the assignment was done serially, since you would get that both would be either equal 1 or 3.
To further prove my point, simply swap the assignment of n and m in your code, and you'll find that the result is the same:
def fibit
n,m =1,1
loop do |variable|
yield n
m,n = n+m,m # this line
puts "n is #{n} m is #{m}"
end
end
fibit do |num|
puts "Next : #{num}"
break if num > 100
end

Ruby: Overloading Yield Function

I noticed while learning Ruby that both of these uses of the each method work and produce the same output, and I was wondering how Ruby makes this happen (and how I can make it happen for my own functions):
my_array = [["hello","goodbye"],["picture","perfect"]]
my_array.each do |array|
puts array[0] + " " + array[1]
end
my_array.each do |first, second|
puts first + " " + second
end
My understanding is that when writing the definition of a method that accepts a code block, the yield method is utilized to pass arguments to the code block and call the block. But how can you utilize the yield method such that it passes different arguments depending on the provided code block? In the example case, it appears that the yield method passes the individual array elements when two parameters (i.e., first, second) are used within the block, and it passes the arrays themselves when one parameter is used within the block (i.e., array).
Neither each not yield are doing anything special here, that's just how block arguments work. Consider this simple example:
def f(x) yield x end
and now we can see what happens:
>> f([1,2]) { |a| puts a.inspect }
[1, 2]
>> f([1,2]) { |a, b| puts "#{a} - #{b}" }
1 - 2
>> f([1,2]) { |a, b, c| puts "#{a} - #{b} - #{c}" }
1 - 2 -
You'll see similar destructing in assignments:
a, b = [1, 2]
You can also do it explicitly with a splat:
a, b = *[1, 2]
or like this:
def g(x) yield *x end
g([1, 2]) { |a, b| puts "#{a} - #{b}" }
Presumably the block knows what sorts of things it will be given so the block is well positioned to unpack the arguments. Note that the g function has to know that its argument is splatable (i.e. an array) but f doesn't. f nicely puts the "what sort of thing is x" logic together in the call to f, g buries half of the logic inside itself. One place where the difference becomes apparent is when you use Enumerable methods on a Hash:
{ :where => :is, :pancakes => :house? }.map { |k, v| ... }
Enumerable#map doesn't need to know that a Hash works in key/value two element arrays, it just passes things around and leaves it up everyone else to worry about the details.

Calling a Ruby method recursively from within its associated block. Any other way?

I've come up with this:
def f x, &b
yield x, b
end
f 4 do |i, b|
p i
f i - 1, &b if i > 0
end
Result:
4
3
2
1
0
Is there another way?
It depends upon the particulars of your actual code, but given your example, if you name the block beforehand, you can avoid yielding the value and the block in your function. Eg:
def f(x, &b)
yield x
end
foo = lambda do |i|
p i
f(i-1,&foo) if i > 0
end
f(4,&foo)
However, I'd like to find a more elegant solution to this problem. I suspect this is would be a good application of the Y combinator. As soon as I have something better for you, I'll update this message.
A block can recursively call itself provided it is stored in a variable that is accessible by the block itself. For example:
def f(x)
block = lambda do |y|
# some calculation on value, or simply yield to the block passed to f()
yield y
block.call(y - 1) if y > 0
end
block.call(x)
end
f(4) do |x|
puts "Yielded block: #{x}"
end
Alternatively, you can return the recursive block, bound to the callers block and then call that block. For example:
def g
block = lambda do |y|
# some calculation on value, or simply yield to block passed to g()
yield y
block.call(y - 1) if y > 0
end
end
printing_descender = g do |x|
puts "Encapsulated block: #{x}"
end
printing_descender.call(4)
Outputs:
Yielded block: 4
Yielded block: 3
Yielded block: 2
Yielded block: 1
Yielded block: 0
Encapsulated block: 4
Encapsulated block: 3
Encapsulated block: 2
Encapsulated block: 1
Encapsulated block: 0
def f(x, &b)
b.call x
f(x-1,&b) if x>0
end
f(4) do |x|
p x
end
Matt's answer is good. It's also the only way to implement an immediate return from a deep recursive search. Note that returning from the block actually returns from the invoking function. unwinding all recursive block calls in one fell swoop.
there are tons of ways to do this using callcc, or catch/throw (which can always return from deep recursive calls). here is non-golfing version that uses thread local vars
def f x, &b
t = Thread.current
t[:b] ||= b
b ||= t[:b]
b.call(x)
ensure
t[:b] = nil
end
f 4 do |i|
p i
f i - 1 if i > 0
end

Resources