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
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
In message "Re: [1.9] Proc#curry"
on Fri, 15 Feb 2008 14:24:33 +0900, David Flanagan <da...@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.
On Fri, 15 Feb 2008 14:24:33 +0900, David Flanagan
<da...@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#[].
--
Ripta Pasay
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.
In message "Re: Proc#curry"
on Sat, 16 Feb 2008 02:35:23 +0900, Trans <tran...@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.
this one:
plus_five = proc { |x,y,z| x, y + z }.curry.call(2).call(3)
plus_five[10] #=> 15
> 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?
--
Phlip
Did you mean x + y + z there Greg?
James Edward Gray II
> > plus_five = proc { |x,y,z| x, y + z }.curry.call(2).call(3)
>
> Did you mean x + y + z there Greg?
Yeah. whoops.
-Tom
-Tom
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 } }
T.
Isn't that partial application not currying per say (one could curry
as a way to implement partial application)?
Brian.
On Feb 15, 8:10 pm, "Brian Mitchell" <binar...@gmail.com> wrote:
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.
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
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. :)
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.
On Feb 16, 8:20 am, Lin Jen-Shin <god...@gmail.com> wrote:
> 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 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.
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
> T.
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.
--
### SER
### Deutsch|Esperanto|Francaise|Linux|XML|Java|Ruby|Haskell|Aikido|Iaido
### http://www.ser1.net, http://www.ser1.net/Security/ser_public.gpg
### Jabber: seaner...@gmail.com (OTR enabled)