Higher Order Functions

N

Nickolay Kolev

Hi guys,

I have recently started learning Ruby having some background in
Python and Prolog. Being a fan of functional programming I want to
port the goopy functions (http://goog-goopy.sourceforge.net/
goopy.functional.html) in Ruby despite most of them having
straightforward equivalents in Ruby already. Just as an exercise. I
also saw it as a good way to teach myself about modules. And
eventually about unit testing. :)

My plan is to put all the functions in a module called Functional and
call them like Functional.func_name(params).

in fruby.rb:

module Functional

def Functional.every(f, lst)
lst.collect { |element| f(element) }
end

end

in test.rb:

require 'fruby'

def times_two(x)
x * 2
end

p Functional.every:)times_two, [1,2,3])


And I get this:

undefined method `f' for Functional:Module (NoMethodError)

How do I pass the times_two function to the module method?

Many thanks in advance!

-- Nicky
 
C

Charles Steinman

Nickolay said:
in fruby.rb:

module Functional

def Functional.every(f, lst)
lst.collect { |element| f(element) }
end

end

in test.rb:

require 'fruby'

def times_two(x)
x * 2
end

p Functional.every:)times_two, [1,2,3])


And I get this:

undefined method `f' for Functional:Module (NoMethodError)

How do I pass the times_two function to the module method?

p Functional.every(method:)times_two), [1,2,3]

And in Functional, it would be lst.collect { |element| f.call(element)
}

Just the token ":times_two" specifies a symbol. This symbol could
represent anything -- a method, a constant, a variable, nothing at all
-- so you use #method to get the method from the current context with a
corresponding name.

As a side note, I assume you realize that this is exactly the sort of
thing blocks are for, right?
 
D

Dave Burt

Nickolay Kolev said:
...
module Functional

def Functional.every(f, lst)
lst.collect { |element| f(element) }
end

end

in test.rb:

require 'fruby'

def times_two(x)
x * 2
end

p Functional.every:)times_two, [1,2,3])


And I get this:

undefined method `f' for Functional:Module (NoMethodError)


The problem here is that f(element) means call the method self.f (which
doesn't exist, hence the error), whereas you want to call the "function"
represented by the parameter f.

You can do this a couple of ways. Charles suggested you pass f as a Method
to every:
p Functional.every(method:)times_two), [1,2,3]
And in Functional, it would be lst.collect { |element| f.call(element)
}

f.call will also work if f is a Proc, so you could also do:
Functional.every(proc{|x| x * 2}, [1, 2, 3])

You can pass a symbol, but I wouldn't recommend it - make the caller pass a
callable object (a Proc or Method).

Cheers,
Dave
 
G

gabriele renzi

Nickolay Kolev ha scritto:
Hi guys,

I have recently started learning Ruby having some background in Python
and Prolog. Being a fan of functional programming I want to port the
goopy functions (http://goog-goopy.sourceforge.net/
goopy.functional.html) in Ruby despite most of them having
straightforward equivalents in Ruby already. Just as an exercise. I
also saw it as a good way to teach myself about modules. And eventually
about unit testing. :)

great plan :) even if I'm a bit disappointed that the library seem to be
(almost) a list handling library.
My plan is to put all the functions in a module called Functional and
call them like Functional.func_name(params).

in fruby.rb:

module Functional

def Functional.every(f, lst)
lst.collect { |element| f(element) }
end

end

Notice you could just do
module Functional
def every... end
def any other... end
extend self
end

so that you could call it via Functiona.f and yet retain the ability to
include the module (say, in Enumerable ;)

I also second the suggetsion to generally use a block wehenever possible
(i.e. 99% of the time)
 
D

Dave Burt

Functional.every(proc{|x| x * 2}, [1, 2, 3])
IMO, you should pass a block.

Then, you still can call it like that:

Functional.every [1,2,3], &method:)foo)

And better yet (IMO) is Ruby's own
[1, 2, 3].collect &method:)foo)

In the spirit of the thing, I'd prefer these functions to be first-class
themselves. Perhaps the most obvious way to do this is:
module Functional
def every
proc do |f, lst|
lst.collect {|element| f[element] }
end
end
end

Which could be used like this:
f = Functional.every
g = proc {|x| x * 2 }
p f[g, [1, 2, 3]]

I'm not up with procs taking blocks; I think it can't be done. And if not,
that's a barrier to using blocks in higher-order functions. You can pass
them as parameters, of course, as in my example.

This is Lispy, though - use square-brackets instead of "call" and you'll
have more brackets than alphanums before you know it!

Cheers,
Dave
 
N

Nickolay Kolev

Hi all,

I was off computers fo a week, sorry for the late thanks. Ideas are
greatly appreciated, I will try them out.

Thanks again.

Nicky
 

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

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,906
Latest member
SkinfixSkintag

Latest Threads

Top