Defining a new function by composition

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" <ehames@gmail.com> schrieb im Newsbeitrag
news:478c16ae0408061209424c2032@mail.gmail.com...

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

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

Thanks,
Ed

···

On Sat, 7 Aug 2004 04:46:25 +0900, Robert Klemme <bob.news@gmx.net> wrote:

"Edgardo Hames" <ehames@gmail.com> schrieb im Newsbeitrag
news:478c16ae0408061209424c2032@mail.gmail.com...
>
> 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

Edgardo Hames wrote:

"Edgardo Hames" <ehames@gmail.com> schrieb im Newsbeitrag
news:478c16ae0408061209424c2032@mail.gmail.com...
   

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 :wink:

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]

···

On Sat, 7 Aug 2004 04:46:25 +0900, Robert Klemme <bob.news@gmx.net> wrote:

--
Mark Sparshatt

"Edgardo Hames" <ehames@gmail.com> schrieb im Newsbeitrag
news:478c16ae0408061345100e8692@mail.gmail.com...

>
> "Edgardo Hames" <ehames@gmail.com> schrieb im Newsbeitrag
> news:478c16ae0408061209424c2032@mail.gmail.com...
> >
> > 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 :wink:

:slight_smile: 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

···

On Sat, 7 Aug 2004 04:46:25 +0900, Robert Klemme <bob.news@gmx.net> wrote:

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

···

On Sat, 7 Aug 2004 06:27:11 +0900, mark sparshatt <msparshatt@yahoo.co.uk> wrote:

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

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

[Edgardo Hames <ehames@gmail.com>, 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]