[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Partial function application (was: Re: Binding precedence for first sym...

e

2/1/2005 5:19:00 AM

Trans wrote:

>>Musing on this, you know what'd be really great? Support for >
>
> partial function application! I suppose this could already be
>
>>emulated (or, more aptly, evamulated), but it could be a really >
>
> useful feature. Those pesky side-effects just get in the way
>
>>but I'm sure that could be overcome :)
>
>
> Forgive me but I have no idea what you are talking about. If you are
> being serious, what is partial function application? What would the
> advantages be? Would the advantage offset the disadvatages it may
> create elsewhere? If you were not, then please don't afford yourself as
> so funny.

Oh, I was serious. Partial function application (also referred to as
'macro binding' and 'currying') means that given a certain function
(or method), e.g.

def fun(x, y, z)
q = x + y + z
end

If this function is invoked with a partial argument list, e.g.

fun 1, 2

Then, instead of throwing some sort of an error, the call would
produce a new function where the given arguments are bound.
Essentially, the previous call would yield:

def fun(z)
q = 1 + 2 + z
end

So these calls would be equal:

fun(1, 2, 3) # => 6
((fun 1, 2) 3) # => 6
fun(1, 2)(3) # => 6
x = fun(1, 2); x(3) # => 6

The only problem would be handling the destructive updates, i.e. what
would happen if one tried to curry this with x:

def fun(x, y, z)
x = x + y + z
end

x can't be directly substituted since it's assigned to. It'd have to
be translated to 'xx = x + y + z' or something.

This probably isn't something most Rubyists, at least initially, would
be excited about but it's quite useful. I think it'd be possible to
implement as a library but it'd obviously be fairly slow. Of course
there's always Haskell :)

> I believe it was Richard Feynman who said, though I paraphrase, "Never
> underestimate the power of a new notation."
>
> T

E



12 Answers

Trans

2/1/2005 5:37:00 AM

0


E S wrote:
> Oh, I was serious. Partial function application (also referred to as
> 'macro binding' and 'currying') means that given a certain function
> (or method), e.g.

Ah, forgive me! I have heared of curry. I like to eat it :-) I have
never noticed these other names for it before.

> def fun(x, y, z)
> q = x + y + z
> end
>
> If this function is invoked with a partial argument list, e.g.
>
> fun 1, 2
>
> Then, instead of throwing some sort of an error, the call would
> produce a new function where the given arguments are bound.
> Essentially, the previous call would yield:
>
> def fun(z)
> q = 1 + 2 + z
> end
>
> So these calls would be equal:
>
> fun(1, 2, 3) # => 6
> ((fun 1, 2) 3) # => 6
> fun(1, 2)(3) # => 6
> x = fun(1, 2); x(3) # => 6

I highly regard this. It should be so.

> The only problem would be handling the destructive updates, i.e. what

> would happen if one tried to curry this with x:
>
> def fun(x, y, z)
> x = x + y + z
> end
>
> x can't be directly substituted since it's assigned to. It'd have to
> be translated to 'xx = x + y + z' or something.

I do not see a problem. The x is local and has no functional baring.
The translation is simply:

fun(1,2) #=>

def fun(1, 2, z)
x = 1 + 2 + z
end

> This probably isn't something most Rubyists, at least initially,
would
> be excited about but it's quite useful. I think it'd be possible to
> implement as a library but it'd obviously be fairly slow. Of course
> there's always Haskell :)
I am for it. Much more so then for my silly symbol notation ;-)

T

Douglas Livingstone

2/1/2005 5:40:00 PM

0

> > def fun(x, y, z)
> > x = x + y + z
> > end
> >
> > x can't be directly substituted since it's assigned to. It'd have to
> > be translated to 'xx = x + y + z' or something.
>
> I do not see a problem. The x is local and has no functional baring.
> The translation is simply:
>
> fun(1,2) #=>
>
> def fun(1, 2, z)
> x = 1 + 2 + z
> end

How about this:

def fun(z)
x = 1
y = 2

# unmodified original
x = x + y + z
end

Then you shouldn't need to worry about rewriting as they would act
more like defult params.

Douglas


Trans

2/1/2005 5:48:00 PM

0

Douglas Livingstone wrote:
> How about this:
>
> def fun(z)
> x = 1
> y = 2
>
> # unmodified original
> x = x + y + z
> end
>
> Then you shouldn't need to worry about rewriting as they would act
> more like defult params.

Nice.

Matt Maycock

2/1/2005 6:41:00 PM

0

On Wed, 2 Feb 2005 02:50:44 +0900, Trans <transfire@gmail.com> wrote:
> Douglas Livingstone wrote:
> > How about this:
> >
> > def fun(z)
> > x = 1
> > y = 2
> >
> > # unmodified original
> > x = x + y + z
> > end
> >
> > Then you shouldn't need to worry about rewriting as they would act
> > more like defult params.
>
> Nice.

This isn't even what he was asking for, though. The OP wanted a
`saved arguments' thing like currying... hardcoding in x and y is the
same as hardcoding 1 and 2 in the q (or x in OP's one example) = x +
y+ z...

Also, I've made a few small updates to my curry file, if anyone is
interested (just default behaviors for certain methods invoked without
any information to use).

Given that the OP mentioned Haskell, I think we should all try to come
up with some language that has the wonderfulness of Haskell with the
wonderful ness of Ruby. We could call it Rascal. Since Haskell cats
are all about domain specific languages, we could call DSLs in Rascal
"Little Rascals"... :-)

~Me!

--
There's no word in the English language for what you do to a dead
thing to make it stop chasing you.


Douglas Livingstone

2/1/2005 6:51:00 PM

0

> This isn't even what he was asking for, though. The OP wanted a
> `saved arguments' thing like currying... hardcoding in x and y is the
> same as hardcoding 1 and 2 in the q (or x in OP's one example) = x +
> y+ z...

I thought that Trans was posting a target for the generated code after
the call to the function is made with too-few arguments. So if
fun(1,2) was called, it would generate and return an object
representing the function I posted above. But the two important steps,
capturing the function call and retruning a "function object", I don't
know how to do :(

I do remember seeing sometihng like def fun:pre() in a slide talking
about Ruby 2 though...

Douglas


Trans

2/1/2005 7:22:00 PM

0

Then again it wouldn't be much different from doing:

class << self
define_method( :"fun(1,2)" do |z|
fun(1,2,z)
end
method :"fun(1,2)"
end

Something like that. And I suspect one should actually alias the
original method first.

T

David Sletten

2/2/2005 9:50:00 AM

0

E S wrote:


>
>
> Oh, I was serious. Partial function application (also referred to as
> 'macro binding' and 'currying') means that given a certain function
> (or method), e.g.
>
> def fun(x, y, z)
> q = x + y + z
> end
>
> If this function is invoked with a partial argument list, e.g.
>
> fun 1, 2
>
> Then, instead of throwing some sort of an error, the call would
> produce a new function where the given arguments are bound.
> Essentially, the previous call would yield:
>
> def fun(z)
> q = 1 + 2 + z
> end
>
> So these calls would be equal:
>
> fun(1, 2, 3) # => 6
> ((fun 1, 2) 3) # => 6
> fun(1, 2)(3) # => 6
> x = fun(1, 2); x(3) # => 6
>
> The only problem would be handling the destructive updates, i.e. what
> would happen if one tried to curry this with x:
>
> def fun(x, y, z)
> x = x + y + z
> end
>
> x can't be directly substituted since it's assigned to. It'd have to
> be translated to 'xx = x + y + z' or something.
>
> This probably isn't something most Rubyists, at least initially, would
> be excited about but it's quite useful. I think it'd be possible to
> implement as a library but it'd obviously be fairly slow. Of course
> there's always Haskell :)
>

This isn't exactly what you were asking for, but it fills some of the
gap. It's a fairly straightforward (i.e., ripped off from) translation
of an example by Paul Graham in _ANSI_Common_Lisp_ (pg. 110). He was
attempting to simulate a similar feature from Dylan.

def curry(f, *args)
lambda {|*args2| f.call(*(args + args2))}
end

fun = lambda {|x, y, z| x + y + z}
fun.call(1, 2, 3) => 6

f1 = curry(fun, 1)
f1.call(2, 3) => 6

f2 = curry(fun, 1, 2)
f2.call(3) => 6

I'm fairly new to Ruby, but I think this is the right way to do this.

David Sletten



Matt Maycock

2/2/2005 4:49:00 PM

0

One thing to make noteworthy are the subtleties bugwise that changing
proc can have on a program (that bit me in the rear a couple of
times)... I think there should definitely be warnings in any file that
does stuff with Proc about such things (as it is entirely subtle, in
my opinion)...

example:

class Proc
def data(arg)
@arg
end
def data=(arg)
@arg = arg
end
end

anon = Proc.new {
p @data
}

def foo
yield
end

anon[] # prints nil
anon.data = 1
anon[] # prints 1
foo(&anon) # prints nil

-- thus, internal data is not kept as the structure is transformed
from proc to block...

~Me!

--
There's no word in the English language for what you do to a dead
thing to make it stop chasing you.


Curt Sampson

2/8/2005 3:12:00 AM

0

Robert Feldt

2/8/2005 11:35:00 AM

0

On Tue, 8 Feb 2005 12:11:42 +0900, Curt Sampson <cjs@cynic.net> wrote:
> On Wed, 2 Feb 2005, Matt Maycock wrote:
>
> > Given that the OP mentioned Haskell, I think we should all try to come
> > up with some language that has the wonderfulness of Haskell with the
> > wonderful ness of Ruby.
>
> Indeed. Count me in as a user of this when you come up with it.
>
I'm also interested in this since they are my main languages (real
order is Ruby, C and Haskell though). They are so very different
though, so I'm not sure what it a mix "would mean". Pattern matching
added to Ruby? Type inference added to Ruby? (would only be a
performance issue? If so would it really change the language?) Dynamic
typing added to Haskell? (Sort of meaningless statement!? ;)) etc...
Maybe a wiki for this somewhere?

Best,

Robert Feldt