Higher Order Functions

Discussion in 'Ruby' started by Nickolay Kolev, Jul 31, 2005.

  1. 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
     
    Nickolay Kolev, Jul 31, 2005
    #1
    1. Advertising

  2. Nickolay Kolev wrote:
    > 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?
     
    Charles Steinman, Jul 31, 2005
    #2
    1. Advertising

  3. Nickolay Kolev

    Dave Burt Guest

    "Nickolay Kolev" <> wrote...
    > ...
    > 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
     
    Dave Burt, Jul 31, 2005
    #3
  4. 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)
     
    gabriele renzi, Jul 31, 2005
    #4
  5. Nickolay Kolev

    Dave Burt Guest

    >> 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
     
    Dave Burt, Jul 31, 2005
    #5
  6. 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
     
    Nickolay Kolev, Aug 8, 2005
    #6
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Jonathan Bartlett

    Higher-Order Programming in C

    Jonathan Bartlett, Mar 31, 2005, in forum: C Programming
    Replies:
    4
    Views:
    305
    Jonathan Bartlett
    Apr 4, 2005
  2. Mark Fink
    Replies:
    3
    Views:
    296
    Arnaud Delobelle
    Dec 22, 2010
  3. Victor \Zverok\ Shepelev

    Higher-order messaging in Ruby

    Victor \Zverok\ Shepelev, Oct 11, 2006, in forum: Ruby
    Replies:
    0
    Views:
    125
    Victor \Zverok\ Shepelev
    Oct 11, 2006
  4. Nate Murray
    Replies:
    13
    Views:
    199
    Gregory Brown
    Jan 5, 2007
  5. Emre Sevinc
    Replies:
    8
    Views:
    148
    Richard Cornford
    Feb 14, 2006
Loading...

Share This Page