Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   Ruby (http://www.velocityreviews.com/forums/f66-ruby.html)
-   -   Defining a new function by composition (http://www.velocityreviews.com/forums/t816022-defining-a-new-function-by-composition.html)

Edgardo Hames 08-06-2004 07:10 PM

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



Robert Klemme 08-06-2004 07:42 PM

Re: Defining a new function by composition
 

"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


Edgardo Hames 08-06-2004 08:45 PM

Re: Defining a new function by composition
 
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


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

Thanks,
Ed



mark sparshatt 08-06-2004 09:27 PM

Re: Defining a new function by composition
 
Edgardo Hames wrote:

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

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




Edgardo Hames 08-06-2004 09:36 PM

Re: Defining a new function by composition
 
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.
>


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



mark sparshatt 08-06-2004 09:37 PM

Re: Defining a new function by composition
 
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
>
>
>





Carlos 08-07-2004 12:00 AM

Re: Defining a new function by composition
 
[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]




Robert Klemme 08-07-2004 09:31 AM

Re: Defining a new function by composition
 

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

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



All times are GMT. The time now is 11:34 AM.

Powered by vBulletin®. Copyright ©2000 - 2013, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57