On Feb 16, 7:48 am, Trans <transf... / gmail.com> wrote:
> On Feb 15, 8:10 pm, "Brian Mitchell" <binar... / gmail.com> wrote:
>
>
>
> > On Fri, Feb 15, 2008 at 5:06 PM, Trans <transf... / gmail.com> wrote:
>
> > >  On Feb 15, 12:46 pm, Yukihiro Matsumoto <m... / ruby-lang.org> wrote:
> > >  > Hi,
>
> > >  > In message "Re: Proc#curry"
>
> > > >     on Sat, 16 Feb 2008 02:35:23 +0900, Trans <transf... / 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?
>
> > >  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 } }
>
> > 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 } }

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.