Defining a new function by composition

Discussion in 'Ruby' started by Edgardo Hames, Aug 6, 2004.

  1. Hi.

    I would like to add a method to the Array class, say Array#pop! which
    is actually split!(-1). But then, I can think of a more general
    problem: define a new function by composition of two or more
    functions.
    In Haskell, I can do something like

    f :: a -> b -> c
    f x y = something

    g::b -> c
    g = f some_value

    What is the Ruby equivalent of this?

    Regards,
    Ed
    Edgardo Hames, Aug 6, 2004
    #1
    1. Advertising

  2. "Edgardo Hames" <> schrieb im Newsbeitrag
    news:...
    > Hi.
    >
    > I would like to add a method to the Array class, say Array#pop! which
    > is actually split!(-1). But then, I can think of a more general
    > problem: define a new function by composition of two or more
    > functions.
    > In Haskell, I can do something like
    >
    > f :: a -> b -> c
    > f x y = something
    >
    > g::b -> c
    > g = f some_value
    >
    > What is the Ruby equivalent of this?
    >
    > Regards,
    > Ed
    >
    >


    How about

    class Array
    def pop!() split!(-1) end
    end

    Note: pop! and split! are not functions but methods. So you always have an
    implicit argument (named 'self' in Ruby). I think this does not lend easily
    to chaining the way you seek.

    Of course, for the general case you could do something like this:

    module Kernel
    private
    def chain(name, *funcs)
    eval "def #{name}(*a) #{funcs.map {|f| "#{f}("}}*a#{")" * funcs.size}
    end"
    end
    end

    >> def foo(x) "<#{x}>" end

    => nil
    >> def bar(x) "[#{x}]" end

    => nil
    >> chain :xxx, :foo, :bar

    => nil
    >> xxx 100

    => "<[100]>"

    Or a more functional approach:

    module Kernel
    private
    def chain2(*funcs)
    lambda {|*a| funcs.inject(a){|val, fun| send(fun, *val) } }
    end
    end

    >> xx2 = chain2 :bar, :foo

    => #<Proc:0x10169340@(irb):61>
    >> xx2.call 100

    => "<[100]>"

    Note the different order.

    Regards

    robert
    Robert Klemme, Aug 6, 2004
    #2
    1. Advertising

  3. On Sat, 7 Aug 2004 04:46:25 +0900, Robert Klemme <> wrote:
    >
    > "Edgardo Hames" <> schrieb im Newsbeitrag
    > news:...
    > >
    > > I would like to add a method to the Array class, say Array#pop! which
    > > is actually split!(-1). But then, I can think of a more general
    > > problem: define a new function by composition of two or more
    > > functions.

    >
    > How about
    >
    > class Array
    > def pop!() split!(-1) end
    > end


    I imagined this. But, I thought you were going to surprise me with a
    weird (or unimagined) way to use alias ;-)

    Thanks,
    Ed
    Edgardo Hames, Aug 6, 2004
    #3
  4. Edgardo Hames wrote:

    >On Sat, 7 Aug 2004 04:46:25 +0900, Robert Klemme <> wrote:
    >
    >
    >>"Edgardo Hames" <> schrieb im Newsbeitrag
    >>news:...
    >>
    >>
    >>>I would like to add a method to the Array class, say Array#pop! which
    >>>is actually split!(-1). But then, I can think of a more general
    >>>problem: define a new function by composition of two or more
    >>>functions.
    >>>
    >>>

    >>How about
    >>
    >>class Array
    >> def pop!() split!(-1) end
    >>end
    >>
    >>

    >
    >I imagined this. But, I thought you were going to surprise me with a
    >weird (or unimagined) way to use alias ;-)
    >
    >
    >

    Though this won't do what you want since there isn't a method split! for
    array.

    I think what you actually want is something like

    class Array
    def pop!
    slice!(-1, 1)
    end
    end

    This discussion did give me an idea for a curry method, that let's you
    predefine the parameters for a method.

    class Class
    def curry(newmethod, oldmethod, stored_params)
    send:)define_method, newmethod) do |*args|
    x = stored_params
    x += args if args
    send(oldmethod, *x)
    end
    end
    end

    then you can define pop! with

    class Array
    curry:)pop!, :slice!, -1, 1)
    end

    then
    x = [1,2,3]
    p x.slice! #=> 3
    p x #=> [1,2]

    --
    Mark Sparshatt
    mark sparshatt, Aug 6, 2004
    #4
  5. On Sat, 7 Aug 2004 06:27:11 +0900, mark sparshatt
    <> wrote:
    >
    > >
    > >

    > Though this won't do what you want since there isn't a method split! for
    > array.
    >


    Since there is a method push which modifies the receiver, I believe
    pop should do the same. I find it kind of odd this isn't so.

    Regards.
    Ed
    Edgardo Hames, Aug 6, 2004
    #5
  6. mark sparshatt wrote:
    [snip]

    >
    > then
    > x = [1,2,3]
    > p x.slice! #=> 3


    that should of course be
    p x.pop! #=> 3

    > p x #=> [1,2]
    >
    > --
    > Mark Sparshatt
    >
    >
    >
    mark sparshatt, Aug 6, 2004
    #6
  7. Edgardo Hames

    Carlos Guest

    [Edgardo Hames <>, 2004-08-06 23.36 CEST]
    > Since there is a method push which modifies the receiver, I believe
    > pop should do the same. I find it kind of odd this isn't so.


    $ ruby -e 'a=[1,2,3]; a.pop; p a'
    [1, 2]
    Carlos, Aug 7, 2004
    #7
  8. "Edgardo Hames" <> schrieb im Newsbeitrag
    news:...
    > On Sat, 7 Aug 2004 04:46:25 +0900, Robert Klemme <> wrote:
    > >
    > > "Edgardo Hames" <> schrieb im Newsbeitrag
    > > news:...
    > > >
    > > > I would like to add a method to the Array class, say Array#pop! which
    > > > is actually split!(-1). But then, I can think of a more general
    > > > problem: define a new function by composition of two or more
    > > > functions.

    > >
    > > How about
    > >
    > > class Array
    > > def pop!() split!(-1) end
    > > end

    >
    > I imagined this. But, I thought you were going to surprise me with a
    > weird (or unimagined) way to use alias ;-)


    :) Not possible because of the argument.

    Here's another solution - even more functional, although I still think this
    looks a bit more elegant in functional languages:

    def concat3(*fun)
    lambda {|*a| fun.inject(a) {|val,f| f.call(*val)} }
    end

    >> foo = lambda {|x| "<#{x}>"}

    => #<Proc:0x1019fac0@(irb):17>
    >> bar = lambda {|x| "[#{x}]"}

    => #<Proc:0x10194d38@(irb):18>
    >> xx3 = concat3 bar, foo

    => #<Proc:0x101b7250@(irb):15>
    >> xx3.call 100

    => "<[100]>"
    >> xx3[ 100 ]

    => "<[100]>"

    As you can see, there are plenty ways to do this. And you can even use Ruby
    as a functional language, although I'd say best use is made of it if you use
    it OO.

    Regards

    robert
    Robert Klemme, Aug 7, 2004
    #8
    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. johny smith
    Replies:
    8
    Views:
    416
    Peter Koch Larsen
    Jul 2, 2004
  2. Alan G Isaac

    Pythonic function composition

    Alan G Isaac, Oct 25, 2004, in forum: Python
    Replies:
    6
    Views:
    433
    Lonnie Princehouse
    Oct 25, 2004
  3. Kay Schluehr
    Replies:
    10
    Views:
    557
    Kay Schluehr
    Feb 4, 2008
  4. Arnaud Delobelle

    An idea for fast function composition

    Arnaud Delobelle, Feb 16, 2008, in forum: Python
    Replies:
    4
    Views:
    330
  5. Tom Moertel

    Function composition in Ruby

    Tom Moertel, Apr 7, 2006, in forum: Ruby
    Replies:
    2
    Views:
    83
    Tom Moertel
    Apr 7, 2006
Loading...

Share This Page