Forum: Ruby-core Proc#curry

Posted by ts (Guest)
on 2008-02-14 18:58
(Received via mailing list)
Do I expect too much from Proc#curry ?

vgs% ./ruby -ve 'a = lambda {|x, y, &b| p b }; b = a.curry[1]; b.call(2) 
{}; a.call(1, 2) {}'
ruby 1.9.0 (2008-02-15 revision 15477) [i686-linux]
nil
#<Proc:0xb7d5d27c@-e:1>
vgs%


 ruby don't see the block



Guy Decoux
Posted by David Flanagan (Guest)
on 2008-02-15 06:25
(Received via mailing list)
ts wrote:
> 
> 
> 
> Guy Decoux
> 

I can't comment on whether or not Guy has found a bug.

I'd like to ask, however, what the rationale is for adding this fairly
major new piece of API after 1.9.0.  I could see this going into the 2.0
development branch, when it opens, but do we need it in 1.9?  (I ask
this, obviously, as someone who has just written and published a book
covering Ruby 1.9--I'd really like the 1.9 API to stay stable!)

Also, what is the use case for currying?  (Functional programming is not
my strong suit, but I thought that currying was mostly of theoretical
interest and a side effect of the fact that lambda calculus only allowed
single arguments to functions.) Is anyone going to use Proc.curry for
anything other than partial application?  If not, wouldn't a papply (or
partial_apply) method be easier and more efficient than the more general
currying?

In that case, Guy's code:

    b = a.curry()[1]   # parens added for clarity

would become

    b = a.papply(1)

  David
Posted by Yukihiro Matsumoto (Guest)
on 2008-02-15 15:30
(Received via mailing list)
Hi,

In message "Re: [1.9] Proc#curry"
    on Fri, 15 Feb 2008 14:24:33 +0900, David Flanagan 
<david@davidflanagan.com> writes:

|I'd like to ask, however, what the rationale is for adding this fairly 
|major new piece of API after 1.9.0.  I could see this going into the 2.0 
|development branch, when it opens, but do we need it in 1.9?  (I ask 
|this, obviously, as someone who has just written and published a book 
|covering Ruby 1.9--I'd really like the 1.9 API to stay stable!)

I consider this method (Proc#curry) to be trivial and should be
treated like an Easter egg for functional programming kids.

              matz.
Posted by Ripta Pasay (Guest)
on 2008-02-15 18:16
(Received via mailing list)
On Fri, 15 Feb 2008 14:24:33 +0900, David Flanagan
<david@davidflanagan.com> wrote:
> 
> Also, what is the use case for currying?  (Functional programming is not
> my strong suit, but I thought that currying was mostly of theoretical
> interest and a side effect of the fact that lambda calculus only allowed
> single arguments to functions.) Is anyone going to use Proc.curry for
> anything other than partial application?  If not, wouldn't a papply (or
> partial_apply) method be easier and more efficient than the more general
> currying?
> 

It is my understanding that a partial application is the reverse of
currying:  A partial application is a binary function that takes a
multi-argument function and returns a function taking fewer arguments.
Currying, on the other hand, is a unary function that "builds" a
multi-argument function from a series of single-argument functions.

So, currying would be done by calling Proc#curry, while apply is done by
calling Proc#[].
Posted by Trans (Guest)
on 2008-02-15 18:36
(Received via mailing list)
On Feb 15, 9:29 am, Yukihiro Matsumoto <m...@ruby-lang.org> wrote:
>
> I consider this method (Proc#curry) to be trivial and should be
> treated like an Easter egg for functional programming kids.

Is there a link where I can read about how this new function works?

(granted, I could go digging through the source, but I figure others
might like to know too)

Thanks,
T.
Posted by Yukihiro Matsumoto (Guest)
on 2008-02-15 18:46
(Received via mailing list)
Hi,

In message "Re: Proc#curry"
    on Sat, 16 Feb 2008 02:35:23 +0900, Trans <transfire@gmail.com> 
writes:

|Is there a link where I can read about how this new function works?

[ruby-dev:33676], if you don't mind seeing Japanese ;-)

If you do mind, it's OK.  It's not difficult at all,

  proc {|x, y, z| x + y + z }.curry

returns the proc object equivalent to

  proc {|x| proc {|y| proc {|z| x + y + z } } }

See?

              matz.
Posted by Phlip (Guest)
on 2008-02-15 19:33
(Received via mailing list)
Yukihiro Matsumoto wrote:

>   proc {|x, y, z| x + y + z }.curry
> 
> returns the proc object equivalent to
> 
>   proc {|x| proc {|y| proc {|z| x + y + z } } }
> 
> See?

Uh, how do we call that?

oookay - proc{...}.call(x).call(y).call(z)

What problem does that solve?
Posted by Gregory Brown (Guest)
on 2008-02-15 19:36
(Received via mailing list)
On Fri, Feb 15, 2008 at 1:33 PM, Phlip <phlip2005@gmail.com> wrote:
>  Uh, how do we call that?
>
>  oookay - proc{...}.call(x).call(y).call(z)
>
>  What problem does that solve?

this one:

plus_five = proc { |x,y,z| x, y + z }.curry.call(2).call(3)

plus_five[10] #=> 15
Posted by James Gray (bbazzarrakk)
on 2008-02-15 19:59
(Received via mailing list)
On Feb 15, 2008, at 12:35 PM, Gregory Brown wrote:

>>
>> Uh, how do we call that?
>>
>> oookay - proc{...}.call(x).call(y).call(z)
>>
>> What problem does that solve?
>
> this one:
>
> plus_five = proc { |x,y,z| x, y + z }.curry.call(2).call(3)

Did you mean x + y + z there Greg?

James Edward Gray II
Posted by Gregory Brown (Guest)
on 2008-02-15 20:14
(Received via mailing list)
On Fri, Feb 15, 2008 at 1:54 PM, James Gray <james@grayproductions.net> 
wrote:

>  > plus_five = proc { |x,y,z| x, y + z }.curry.call(2).call(3)
>
>  Did you mean x + y + z there Greg?

Yeah.  whoops.
Posted by Thomas Enebo (Guest)
on 2008-02-15 21:19
(Received via mailing list)
Gregory Brown wrote:
>>  > See?
> plus_five = proc { |x,y,z| x, y + z }.curry.call(2).call(3)
>
> plus_five[10] #=> 15
>
>   
Also in some languages the 2 + 3 can be optimized to only happen once.
Doesn't look like it will here though?

-Tom
Posted by Thomas Enebo (Guest)
on 2008-02-15 21:22
(Received via mailing list)
Thomas Enebo wrote:
>>>  >
>>
>> plus_five = proc { |x,y,z| x, y + z }.curry.call(2).call(3)
>>
>> plus_five[10] #=> 15
>>
>>   
> Also in some languages the 2 + 3 can be optimized to only happen 
> once.   Doesn't look like it will here though?
Ignore the question part of that...I have a minor head code today :)

-Tom
Posted by Trans (Guest)
on 2008-02-15 23:07
(Received via mailing list)
On Feb 15, 12:46 pm, Yukihiro Matsumoto <m...@ruby-lang.org> wrote:
>
>   proc {|x, y, z| x + y + z }.curry
>
> returns the proc object equivalent to
>
>   proc {|x| proc {|y| proc {|z| x + y + z } } }
>
> See?

Yep. I see.

It is rather trivial, I agree. Unfortunately maybe too trivial because
were stuck with the order of arguments. Or doe curry take some
argument to vary that? To clarify what I mean, Facets has an
implementation of curry, for both Proc and Method, like so:

  proc {|x, y, z| x + y + z }.curry(__,__,__)

Of course I like your better in this case ;-)  BUT, it does allow:

  proc {|x, y, z| x + y + z }.curry(__,5,__)

for:

  proc {|x| proc {|z| x + 5 + z } }

T.
Posted by Brian Mitchell (Guest)
on 2008-02-16 02:11
(Received via mailing list)
On Fri, Feb 15, 2008 at 5:06 PM, Trans <transfire@gmail.com> wrote:
>  > [ruby-dev:33676], if you don't mind seeing Japanese ;-)
>
>
>   proc {|x, y, z| x + y + z }.curry(__,5,__)
>
>  for:
>
>   proc {|x| proc {|z| x + 5 + z } }
>

Isn't that partial application not currying per say (one could curry
as a way to implement partial application)?

Brian.
Posted by Trans (Guest)
on 2008-02-16 13:49
(Received via mailing list)
On Feb 15, 8:10 pm, "Brian Mitchell" <binar...@gmail.com> wrote:
>
> >  > See?
> >  Of course I like your better in this case ;-)  BUT, it does allow:
>
> >   proc {|x, y, z| x + y + z }.curry(__,5,__)
>
> >  for:
>
> >   proc {|x| proc {|z| x + 5 + z } }
>
> Isn't that partial application not currying per say (one could curry
> as a way to implement partial application)?

I've also heard it called "partial currying". I'd rather have a
superset of funtionality then a subset. Currying is about isolating a
single argument. It doesn't dictate in which argument to isolate. It
could be x, y, or z, etc. Nor does it mean currying every variable all
the way down that line.

If we give matz's curry function an arity-slot number as an optional
argument, then we could do it all like so:

  P = proc { |x,y,z| x+y+z }
  P.curry(1) => proc { |y| proc |x,z| x+y+z } }

Which would then allow partial applicaiton via:

 P.curry(1)[5]

A second argument could dictate the next level of currying

  P.curry(1,1) => proc { |y| proc |z| proc |x| x+y+z } }

T.
Posted by Wolfgang Nádasi-Donner (wonado)
on 2008-02-16 14:19
(Received via mailing list)
Yukihiro Matsumoto schrieb:
>   proc {|x, y, z| x + y + z }.curry
> 
> returns the proc object equivalent to
> 
>   proc {|x| proc {|y| proc {|z| x + y + z } } }

This is what I would expect from "currying" (or schönfinkeln). So I
would expect, that the calls will be...

proc {|x, y, z| x + y + z }[1,2,3]
proc {|x, y, z| x + y + z }.curry[1][2][3]

...with the same result, but that...


proc {|x, y, z| x + y + z }.curry[1,2,3]

would fail with the message "3 parameters instead of 1". I'm a little
bit surprized, that ist works...

boviMacBook:~ bovi$ ruby19 --version
ruby 1.9.0 (2008-02-16 revision 0) [i686-darwin9.1.0]
boviMacBook:~ bovi$ irb19
irb(main):001:0> f = proc{|a,b,c|a+b+c}
=> #<Proc:0x3ce9c0@(irb):1>
irb(main):002:0> g = f.curry
=> #<Proc:0x3cc2d8>
irb(main):003:0> f[1,2,3]
=> 6
irb(main):004:0> g[1][2][3]
=> 6
irb(main):005:0> def otto(fun)
irb(main):006:1>   fun[3,4]
irb(main):007:1> end
=> nil
irb(main):008:0> r = proc{|k,l|k*l}
=> #<Proc:0x3bc0b8@(irb):8>
irb(main):009:0> s = proc{|m,n,o|m+n+o}.curry
=> #<Proc:0x3b69ec>
irb(main):010:0> otto(r)
=> 12
irb(main):011:0> otto(s[2])
=> 9

Is this an accident or done by intention. If it is done by intention it
is nice, because otherwise I must implement an application which uses
currying with currying all Proc objects that use more than one 
parameter.

Wolfgang Nádasi-Donner
Posted by Lin Jen-Shin (Guest)
on 2008-02-16 14:21
(Received via mailing list)
On Feb 16, 6:06 am, Trans <transf...@gmail.com> wrote:
>
>   proc {|x, y, z| x + y + z }.curry(__,5,__)
>
> for:
>
>   proc {|x| proc {|z| x + 5 + z } }
>
> T.

You might want to have a look at gem ludy for Proc#bind,
http://ludy.rubyforge.org/classes/Proc.html#M000042

I'd written Proc#curry as well, so you can write as following:

godfat ~> irb
irb(main):001:0> require 'rubygems'
=> true
irb(main):002:0> require 'ludy/proc'
=> true
irb(main):003:0> lambda{|x,y,z|[x,y,z]}.curry.bind(:_1, 2, :_2)[1,3]
=> [1, 2, 3]

I am glad to see Proc#curry can be added into core, not supporting
with library,
but I didn't see there's Proc#uncurry as well. I hope there's one too.

Functional programming matters. :)
Posted by Trans (Guest)
on 2008-02-26 19:01
(Received via mailing list)
On Feb 16, 7:48 am, Trans <transf...@gmail.com> wrote:
>
> > >  > returns the proc object equivalent to
> > >  implementation of curry, for both Proc and Method, like so:
>
> argument, then we could do it all like so:
>   P.curry(1,1) => proc { |y| proc |z| proc |x| x+y+z } }
Here is an example implementation:

  class Proc

    def curry(*args)
      if args.empty?
        idx = (0...arity).to_a
      else
        raise ArgumentError, "argument count is greater than arity
(#{args.size} > #{arity})" if args.size > arity
        raise ArgumentError, "arguments must be unique indexes" if
args.uniq != args
        raise ArgumentError, "arguments must be indexes" if args.any?
{ |a| !Fixnum===a }
        idx = (0...arity).to_a
        idx = args + (idx - args)
      end

      rec = ''
      idx.each do |i|
        rec << "proc { |a#{i}| "
      end
      rec << "self["
      rec << (0...arity).to_a.collect{|i| "a#{i}"}.join(',')
      rec << "]"
      rec << "}" * arity

      instance_eval rec
    end

  end

Example:

>> a = proc { |x,y| x**y }
=> #<Proc:0x00002aae4fd50638@(irb):5>
>> b = a.curry(0)
=> #<Proc:0x00002aae4fd4b110@(eval):1>
>> c = a.curry(1)
=> #<Proc:0x00002aae4fd45aa8@(eval):1>
>> b[2][3]
=> 8
>> c[2][3]
=> 9

I'd appreciate suggestions for improvement, as I certainly expect
there are a plenty.

T.
Posted by Trans (Guest)
on 2008-02-26 19:22
(Received via mailing list)
On Feb 16, 8:20 am, Lin Jen-Shin <god...@gmail.com> wrote:

> => [1, 2, 3]
I suspect you did not need the call to #curry there?

Interesting, does it allow .bind(:_1, 2, :_1)[3] ?

> I am glad to see Proc#curry can be added into core, not supporting
> with library,
> but I didn't see there's Proc#uncurry as well. I hope there's one too.

Is it a full reversible processes?

T.
Posted by Lin Jen-Shin (Guest)
on 2008-02-29 16:17
(Received via mailing list)
On Feb 27, 2:21 am, Trans <transf...@gmail.com> wrote:
> On Feb 16, 8:20 am, Lin Jen-Shin <god...@gmail.com> wrote:
> > godfat ~> irb
> > irb(main):001:0> require 'rubygems'
> > => true
> > irb(main):002:0> require 'ludy/proc'
> > => true
> > irb(main):003:0> lambda{|x,y,z|[x,y,z]}.curry.bind(:_1, 2, :_2)[1,3]
> > => [1, 2, 3]
>
> I suspect you did not need the call to #curry there?

Yes, you're right. I forgot to fix my example there (it's just simply
copied from rdoc), and later I changed the example to:

lambda{|x,y,z|[x,y,z]}.curry.bind(:_1, 2, :_2)[1][3]

I found that it didn't work as I expected, [1,2,3] but nil instead.
It came from calling [1,2,nil][3]. The curry thing didn't work on
bind.
I think I would spend some time on fixing this.

> Interesting, does it allow .bind(:_1, 2, :_1)[3] ?

Yes, it was allowed. The result would be [3,2,3].
Bind just simply creates a lambda which rearranges the arguments
for the calling Proc object.

> > I am glad to see Proc#curry can be added into core, not supporting
> > with library,
> > but I didn't see there's Proc#uncurry as well. I hope there's one too.
>
> Is it a full reversible processes?

Yes, it is. See example in Haskell, which make all function
default to be curried. I won't explain the example here because
this is ruby-core mailing list, neither Haskell nor functional
programming.
I am very glad to see if more FP stuffs are added into ruby core
language.

godfat ~> ghci
GHCi, version 6.8.2: http://www.haskell.org/ghc/  :? for help
Loading package base ... linking ... done.
Prelude> let func = \x y -> x + y
Prelude> func 1 2
3
Prelude> (func 1) 2
3
Prelude> :type func
func :: Integer -> Integer -> Integer

Prelude> uncurry func (1,2)
3
Prelude> :type uncurry func
uncurry func :: (Integer, Integer) -> Integer

Prelude> curry (uncurry func) 1 2
3
Prelude> :type curry (uncurry func)
curry (uncurry func) :: Integer -> Integer -> Integer
Posted by Sean E. Russell (Guest)
on 2008-03-01 11:46
(Received via mailing list)
On Friday 15 February 2008, Yukihiro Matsumoto wrote:
>     on Fri, 15 Feb 2008 14:24:33 +0900, David Flanagan 
<david@davidflanagan.com> writes:
> |I'd like to ask, however, what the rationale is for adding this fairly
> |major new piece of API after 1.9.0.  I could see this going into the 2.0
> |development branch, when it opens, but do we need it in 1.9?  (I ask
> |this, obviously, as someone who has just written and published a book
> |covering Ruby 1.9--I'd really like the 1.9 API to stay stable!)
>
> I consider this method (Proc#curry) to be trivial and should be
> treated like an Easter egg for functional programming kids.

Actually, you didn't refute David's implied assertion that the 1.9 API 
must be
stable, and this makes me nervous.

Isn't Ruby 1.9's API -- by definition -- unstable?  If we can't make API
changes in the unstable branches, where can we make them?  This is a 
fairly
important piece of information that developers have to know, and if I've 
been
making the wrong assumption, I'd like to know.

Thanks.
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.