About functional programming


#1

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)


#2

gaoxtwarrior wrote:

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 {…}) { … }


#3

On 06.04.2007 07:11, gaoxtwarrior wrote:

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+(x3)}
=> 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


#4

On Apr 6, 1:15 am, “gaoxtwarrior” removed_email_address@domain.invalid wrote:

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.


#5

On 4/6/07, Joel VanderWerf removed_email_address@domain.invalid wrote:

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.


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/


#6

On Apr 6, 2007, at 1:15 AM, gaoxtwarrior wrote:

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 W.


#7

On 4/7/07, Joel VanderWerf removed_email_address@domain.invalid wrote:

from a block lamba is almost always the right choice.

 return

puts “didn’t get here”
foo_lambda
foo_proc_new
done


vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Also, Proc.new (and proc in 1.9) do not check arguments strictly:

mylam = Proc.new {|x,y,z| p ‘hi’ }
=> #Proc:0x013fc75c@:3(irb)

mylam[1,2,3,4,5,6,7]
“hi”
=> nil

mylam[]
“hi”
=> nil


#8

Rick DeNatale wrote:

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


#9

On 4/7/07, Rick DeNatale removed_email_address@domain.invalid wrote:

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”)


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/


#10

On 4/7/07, Joel VanderWerf removed_email_address@domain.invalid wrote:

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.


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/