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
on 2008-02-14 18:58
on 2008-02-15 06:25
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
on 2008-02-15 15:30
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.
on 2008-02-15 18:16
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#[].
on 2008-02-15 18:36
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.
on 2008-02-15 18:46
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.
on 2008-02-15 19:33
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?
on 2008-02-15 19:36
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
on 2008-02-15 19:59
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
on 2008-02-15 20:14
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.
on 2008-02-15 21:19
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
on 2008-02-15 21:22
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
on 2008-02-15 23:07
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.
on 2008-02-16 02:11
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.
on 2008-02-16 13:49
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.
on 2008-02-16 14:19
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
on 2008-02-16 14:21
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. :)
on 2008-02-26 19:01
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.
on 2008-02-26 19:22
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.
on 2008-02-29 16:17
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
on 2008-03-01 11:46
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
Log in with Google account | Log in with Yahoo account
No account? Register here.