about functional programming

G

gaoxtwarrior

when it comes the method needs two block to accomplish a task,how the ruby
do which? for example , the classical sum(filter,mapping,iterator)(I have
forgotten the style, maybe,the one can search it in SICP)
 
J

Joel VanderWerf

gaoxtwarrior said:
when it comes the method needs two block to accomplish a task,how the ruby
do which? for example , the classical sum(filter,mapping,iterator)(I have
forgotten the style, maybe,the one can search it in SICP)

If the two blocks are applied sequentially, as part of two separate
iterations, it's straightforward:

[1,2,"fred","wilma",5,6].select{|x|x.kind_of?(Numeric)}.inject{|s,x|s+x}
=> 14

In this special case, we can use #grep because testing for
x.kind_of?(Numeric) is the same as testing Numeric === x (which is what
grep(Numeric) does):

[1,2,"fred","wilma",5,6].grep(Numeric).inject{|s,x|s+x}
=> 14

More generally, though, the only way to pass more than one block to a
method is to turn all but one of the blocks into procs, like this:

meth_with_two_blocks(proc {...}) { ... }
 
G

Gary Wright

when it comes the method needs two block to accomplish a task,how
the ruby
do which? for example , the classical sum(filter,mapping,iterator)
(I have
forgotten the style, maybe,the one can search it in SICP)

Ruby's block syntax is just a special (and very useful) case for a
single
block but you can construct proc objects and pass them directly if you
you have a need:

def merge(a,b,c)
[a.call, b.call, c.call].join('/')
end

result = merge( proc { "first block" }, proc { "second block"}, proc
{ "third block" } )

puts result # "first block/second block/third block"



Gary Wright
 
R

Robert Klemme

when it comes the method needs two block to accomplish a task,how the ruby
do which? for example , the classical sum(filter,mapping,iterator)(I have
forgotten the style, maybe,the one can search it in SICP)

A straightforward way would be

irb(main):001:0> num=(1..10).to_a
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
irb(main):002:0> num.select {|x| x<5}.inject(0) {|sum,x| sum+x}
=> 10
irb(main):003:0> num.select {|x| x<5}.inject(0) {|sum,x| sum+(x*3)}
=> 30
irb(main):012:0> num.select {|x| x<5}.map {|x| x*3}.inject(0) {|sum,x|
sum+x}
=> 30

You don't need the "iterator" argument because you typically define
these methods in Enumerable.

Other than that you can of course combine filter and mapping by mapping
values that are not included in the filter to 0:

irb(main):004:0> num.inject(0) {|sum,x| sum+(x < 5 ? x*3 : 0)}
=> 30

As has been pointed out, if you want to define a method "sum" that
accepts a filter and a mapping, you would have to provide at least one
of the two blocks via proc / lambda.

HTH

robert
 
T

Trans

when it comes the method needs two block to accomplish a task,how the ruby
do which? for example , the classical sum(filter,mapping,iterator)(I have
forgotten the style, maybe,the one can search it in SICP)

You can cache one block and wait on the other, from another method,
eg.


foo{ block1 }.bar{ block2 }

Like so:

def foo(&b)
@foo = b
self
end

def bar(&b)
#do stuff with @foo and b
end

T.
 
R

Rick DeNatale

More generally, though, the only way to pass more than one block to a
method is to turn all but one of the blocks into procs, like this:

meth_with_two_blocks(proc {...}) { ... }

I generally recommend using Kernel#lambda instead of Kernel#proc the
difference is subtle, but unless you want to allow non-local returns
from a block lamba is almost always the right choice.
 
J

Joel VanderWerf

Rick said:
I generally recommend using Kernel#lambda instead of Kernel#proc the
difference is subtle, but unless you want to allow non-local returns
from a block lamba is almost always the right choice.

Do you mean Proc.new? IIRC Kernel#proc and Kernel#lambda are aliases.
Proc.new is the one with non-local returns, at least as of 1.8.6.[1]

There is another reason to not use #proc, which I have yet to resign
myself to: it is going away in some future ruby, and we will have to
type two more characters each time we want to use it.



[1]

def m
foo_lambda = lambda do
puts "foo_lambda"
return
end

foo_proc = proc do
puts "foo_proc"
return
end

foo_proc_new = Proc.new do
puts "foo_proc_new"
return # non-local return
end

foo_proc.call
foo_lambda.call
foo_proc_new.call
puts "didn't get here"
end

m
puts "done"

__END__

Output:

foo_proc
foo_lambda
foo_proc_new
done
 
C

Chris Carter

Rick said:
I generally recommend using Kernel#lambda instead of Kernel#proc the
difference is subtle, but unless you want to allow non-local returns
from a block lamba is almost always the right choice.

Do you mean Proc.new? IIRC Kernel#proc and Kernel#lambda are aliases.
Proc.new is the one with non-local returns, at least as of 1.8.6.[1]

There is another reason to not use #proc, which I have yet to resign
myself to: it is going away in some future ruby, and we will have to
type two more characters each time we want to use it.



[1]

def m
foo_lambda = lambda do
puts "foo_lambda"
return
end

foo_proc = proc do
puts "foo_proc"
return
end

foo_proc_new = Proc.new do
puts "foo_proc_new"
return # non-local return
end

foo_proc.call
foo_lambda.call
foo_proc_new.call
puts "didn't get here"
end

m
puts "done"

__END__

Output:

foo_proc
foo_lambda
foo_proc_new
done

Also, Proc.new (and proc in 1.9) do not check arguments strictly:
mylam = Proc.new {|x,y,z| p 'hi' }
=> # said:
mylam[1,2,3,4,5,6,7]
"hi"
=> nil
"hi"
=> nil
 
R

Rick DeNatale

Do you mean Proc.new? IIRC Kernel#proc and Kernel#lambda are aliases.
Proc.new is the one with non-local returns, at least as of 1.8.6.[1]

Yep you're right. I got the difference between a raw proc and a
lambda and the two methods.
There is another reason to not use #proc, which I have yet to resign
myself to: it is going away in some future ruby, and we will have to
type two more characters each time we want to use it.

Personally, I prefer lambda to proc, particularly since we are talking
about functional programming.

Makes me think of Alonzo Church every time I type it.

And Ruby saves me so many characters in so many other contexts
compared to most languages that it seems like a small thing anyway.
<G>
 
R

Rick DeNatale

Yep you're right. I got the difference between a raw proc and a
lambda and the two methods.

"I got the difference between a raw proc and a lambda and the two
methods.".sub(/lambda/,"lambda,").sub(/methods/, "methods tied
together in my feeble mind")
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,239
Messages
2,571,200
Members
47,840
Latest member
Tiffany471

Latest Threads

Top