How to yield 2 blocks in 1 method - ruby

How can I yield two diferent blocks in the same method
the example code:
def by_two(n,a)
yield n
yield a
end
proc1 = proc {|x| p x * 2}
proc2 = proc {|x| x + 100}
by_two(10, 300, &proc1, &proc2)
the error is such -
main.rb:7: syntax error, unexpected ',', expecting ')'
by_two(10, 300, &proc1, &proc2)
Any suggestions where and what is wrong? Thanks

Blocks are a lightweight way of passing a single anonymous procedure to a method. So, by definition, there cannot be two blocks passed to a method. It's not just semantically impossible, it isn't even possible syntactically.
Ruby does support first-class procedures in the form of Procs, however, and since those are just objects like any other object, you can pass as many of them as you want:
def by_two(n, a, proc1, proc2)
proc1.(n)
proc2.(a)
end
proc1 = proc {|x| p x * 2}
proc2 = proc {|x| x + 100}
by_two(10, 300, proc1, proc2)
# 20
# => 400
Since the introduction of lambda literals in Ruby 1.9, Procs are almost as syntactically lightweight as blocks, so there is not a big difference anymore:
by_two(10, 300, -> x { p x * 2 }, -> x { x + 100 })
# 20
# => 400

You cannot yield two blocks in a method.
But you can take two procs.
def by_two(n, a, pr1, pr2)
pr1.call(n)
pr2.call(a)
end
by_two(10, 300, proc1, proc2)

The answer to your question is: You cannot do it if you insist on blocks! Ruby does not support multiple blocks per method. A way to go around this is to pass two procs as variables like this:
def by_two(n,a, proc1=nil, proc2=nil)
if proc1 || proc2
proc1.yield n if proc1
puts proc2.yield a if proc2
else
puts "no procs"
end
end
proc1 = proc {|x| p x * 2}
proc2 = proc {|x| x + 100}
by_two(10, 300, proc1, proc2)
by_two(10, 300, proc1)
by_two(10, 300)
Output:
20
400
20
no procs
Another possibility is this:
NO_OP = proc {}
def by_two(n,a, proc1=NO_OP, proc2=NO_OP)
if proc1 == NO_OP && proc2 == NO_OP
puts "no procs"
else
proc1.yield n
proc2.yield a
end
end
proc1 = proc {|x| p x * 2}
proc2 = proc {|x| p x + 100}
by_two(10, 300, proc1, proc2)
by_two(10, 300, proc1)
by_two(10, 300)
It has the same output.

Related

Printing output results to one line in the console

Is there an easy way to have the results listed in a single line? For example,
"The numbers outputted were: 99, 85, 70, 50, 35, 20, -2"
def randomMethod()
rand1 = rand(2)
if rand1 == 1
rand2 = rand(1..25)
puts rand2
else
rand2 = 0
puts rand2
end
rand2
end
x = 99
#prints initial x
puts "x = " + "#{x}"
loop do
x -= randomMethod # decrement x by the value returned by randomMethod
puts "x = #{x}"
break if x <= 0
end
Don't use puts in a loop, it terminates with a newline. Instead, accumulate the values in an array and join them with commas once the set is complete:
x_vals = [99]
x_vals << x_vals.last - randomMethod while x_vals.last > 0
puts "The numbers were: #{x_vals.join(", ")}"
While you're at it, you could really tighten up your random method. I'm changing the name to be more conformant with Ruby norms:
def random_method
outcome = rand(1..25) * rand(2)
puts outcome
outcome
end
and if you don't actually need to print the value being generated each time you can completely lose the temporary variables:
def random_method
rand(1..25) * rand(2)
end

Passing procs and methods

I came across this code:
squareIt = Proc.new do |x|
x * x
end
doubleIt = Proc.new do |x|
x + x
end
def compose proc1, proc2
Proc.new do |x|
proc2.call(proc1.call(x))
end
end
doubleThenSquare = compose(doubleIt, squareIt)
squareThenDouble = compose(squareIt, doubleIt)
doubleThenSquare.call(5)
squareThenDouble.call(5)
doubleThenSquare is called with 5. doubleThenSquare is equal to the return value of compose, which has its two parameters doubleIt and squareIt passed.
I don't see how 5 is passed all its way into the different procs Proc.new do |x|. How does it know what x is in each case?
Let's step through it.
doubleIt = Proc.new do |x|
x + x
end
#=> #<Proc:0x00000002326e08#(irb):1429>
squareIt = Proc.new do |x|
x * x
end
#=> #<Proc:0x00000002928bf8#(irb):1433>
proc1 = doubleIt
proc2 = squareIt
compose returns the proc proc3.
proc3 = Proc.new do |x|
proc2.call(proc1.call(x))
end
#=> #<Proc:0x000000028e7608#(irb):1445>
proc3.call(x) is executed in the same way as
proc3_method(x)
where
def proc3_method(x)
y = proc1.call(x)
proc2.call(y)
end
When x = 5,
y = proc1.call(5)
#=> 10
proc2.call(10)
#=> 100
proc3_method(5) therefore returns 100, as does proc3.call(5).

Ruby find max number w/o running method twice

I want to find the max number without running the function twice
def foo(num)
num * 10
end
def bar
x = 0
for i in 0..5
if foo(i) > x
x = foo(i) # I don't want to run foo a second time
end
end
end
How about
def bar
(1..5).map{|i| foo(i)}.max
end
This will traverse 1 to 5, and max a new enumerable with foo(i) instead of i, then return the max.
If you want the value of x:
define_method(:foo) { |x| x * 10 }
(1..5).max_by { |x| foo(x) }
#=> 5
If you want the value of f(x):
(1..5).map { |x| foo(x) }.max
#=> 50
You can save the result of the function as a variable, so you can use it later without calling the function again.
Applied to your code example, it would look like this:
#...
fooOfI = foo(i)
if fooOfI > x
x = fooOfI
end
#...
Store the result of the method in a local variable.
def bar
x = 0
for i in 0..5
foo_result = foo i
if foo_result > x
x = foo_result
end
end
end
I would do some change in your code :
def foo(num)
num * 10
end
def bar
x = 0
for i in 0..5
_,x = [foo(i),x].sort #or you can write as x = [foo(i),x].max
end
x
end
p bar
# >> 50
Elegant and simple
foo = -> x { x * 10 }
(1..5).map(&foo).max
# => 50
In one iteration (no so elegant but performs better)
def foo(num); num * 10; end;
(1..5).reduce(-1.0/0) { |a, e| f = foo(e); f > a ? f : a }
# => 50

Defining algebra on Proc

I am trying to define conjunction Proc#* and disjunction Proc#+ on Proc class. When the receiver and the argument have different arity, then it should raise an error. Otherwise, it should return a proc object that is conjunction/disjunction, respectively. I implemented them as follows:
class Proc
def * other
raise ArgumentError, "Arity does not match" unless arity == other.arity
->(*args){call(*args) and other.call(*args)}
end
def + other
raise ArgumentError, "Arity does not match" unless arity == other.arity
->(*args){call(*args) or other.call(*args)}
end
end
This works well with simple procs:
p = ->x{x % 2 == 0} * ->x{x % 3 == 0}
p.call(2) # => false
p.call(6) # => true
but it raises an error when I further try to build on the result of these methods:
q = p * ->x{x % 5 == 0}
# => Error, Arity does not match
This is because the arity of ->x{x % 5 == 0} is 1, whereas the arity of p is -1 due to call(*args) in my implementation.
Is there any good way to make the methods Proc#* and Proc#+ work recursively?
If I remove the raise ... from the definition, then it will work, but then, it will return misleading error messages when procs with different arity are conjoined/disjoined. For example, suppose the raise ... part is deleted from the definition above, and I do:
p = ->x{x % 2 == 0} * ->x, y, z{x % 3 == 0}
then Proc#* will not raise an error, but will return a valid proc object. However, since part of it requires one argument and another part requires three arguments, there would be no way to pass arguments to p in a valid way.
p.call(2) # => error
will raise an ArgumentError, saying:
Wrong number of arguments
but the mistake actually happened when creating p that cannot be satisfied with any number of arguments, and the error message would be misleading. That is why I added the raise ... check. Is removing the raise ... only way to make it work?
I think you probably need to remove the raise because procs that take variable numbers of arguments can be validly called but have different arity values. For example
p = ->(a) {} * (a, *args) {}
p.call(1) # valid
p.call(1,2) # invalid
Maybe a solution would be to improve the error message within the returned lambda? Something like
lambda(*args) do
raise "wrong number of arguments for left lambda" if (arity < 0 && arity.abs - 1 <= args.size) || (arity > 0 && arity != args.size)
# etc (not sure those cases are exactly right)
call(*args) and other.call(*args)
end
It may be easier to use the parameters method, which will spell out the required, optional and splat parameters. Should make it easy to check if it will never be possible to call the resulting lambda and throw an error on creation in that case.
One possible way is to extend Proc:
class MyProc < Proc
attr_reader :my_arity
def initialize(my_arity = nil, &block)
#my_arity = my_arity || block.arity
super(&block)
end
def *(other)
other = MyProc.new(&other)
raise "Arity error" unless my_arity == other.my_arity
MyProc.new(my_arity, &->(*args){ call(*args) && other[*args] })
end
end
p (MyProc.new(&->(x, y){ x == y }) * ->(x, y){ x == y } * ->(x, y){ x == y })[1,1] #=> true
p (MyProc.new(&->(x, y){ x == y }) * ->(x, y){ x == y } * ->(x, y){ x != y })[1,1] #=> false
p (MyProc.new(&->(x, y){ x == y }) * ->(x, y){ x == y } * ->(x){ x })[1,1] #=> exception

Ruby 1.9 enumeration changes

So, I don't quite get Ruby 1.9 's changes on enumerators, but what I'd like is a lazy filtering/mapping on a collection, so for example how can I create a lazy enumerator that would be the equivalent of this ...
(1..100).find_all{|x| x % 2 == 1}.map{|x| x * 2}.find_all{|x| x % 3 == 0}
I tried passing a lambda to #enum_for, but it doesn't work on my machine.
You can find implementations of lazy_select and lazy_map in this blog. You will just have to extend the Enumerator module by those two methods. Then you should be able to use
(1..100).lazy_select{|x| x % 2 == 1}.lazy_map{|x| x * 2}.lazy_select{|x| x % 3 == 0}
Sadly, you can't do this with enum_for. You have to use something like this for lazy enumerables:
class LazyEnum
include Enumerable
attr_accessor :enum, :operations
def initialize enum
#enum = enum
#operations = []
end
def each
enum.each do |x|
filtered = false
operations.each do |type, op|
if type == :filter
unless op[x]
filtered = true
break
end
else
x = op[x]
end
end
yield x unless filtered
end
end
def map! &blk
#operations << [:transform, blk]
self
end
def select! &blk
#operations << [:filter, blk]
self
end
def reject!
select! {|x| !(yield x)}
end
def dup
LazyEnum.new self
end
def map &blk
dup.map! &blk
end
def select &blk
dup.select! &blk
end
def reject &blk
dup.reject! &blk
end
end
LazyEnum.new(1..100).select{|x| x % 2 == 1}.map{|x| x * 2}.select{|x| x % 3 == 0}
#=> #<LazyEnum:0x7f7e11582000 #enum=#<LazyEnum:0x7f7e115820a0 #enum=#<LazyEnum:0x7f7e11582140 #enum=#<LazyEnum:0x7f7e115822d0 #enum=1..100, #operations=[]>, #operations=[[:filter, #<Proc:0x00007f7e11584058#(irb):348>]]>, #operations=[[:transform, #<Proc:0x00007f7e11583a90#(irb):348>]]>, #operations=[[:filter, #<Proc:0x00007f7e115823c0#(irb):348>]]>
irb(main):349:0> LazyEnum.new(1..100).select{|x| x % 2 == 1}.map{|x| x * 2}.select{|x| x % 3 == 0}.to_a
#=> [6, 18, 30, 42, 54, 66, 78, 90, 102, 114, 126, 138, 150, 162, 174, 186, 198]

Resources