From: boris@... Date: 2014-02-21T18:54:22+00:00 Subject: [ruby-core:60952] [ruby-trunk - Feature #7939] Alternative curry function creation Issue #7939 has been updated by Boris Stitnicky. Thanks to Yui Naruse for reopening this issue. As a matter of fact, I hate the current behavior of `#curry` method with passion. In line with the OP suggestion, I propose to define `#curry` as follows: ```ruby class Proc def curry *args hash = args[0] ordered_curry, named_curry = hash.each_with_object [{}, {}] do |(k, v), m| case k when Integer then m[0][k] = v when Symbol then m[1][k] = v else fail ArgumentError end end ordered_min_size = ordered_curry.keys.max o = -> *args { loop.with_index.with_object [] do |(_, i), ary| break ary if args.empty? and i > ordered_min_size ary << ( ordered_curry[ i ] || args.shift ) end } n = -> **named_args { named_curry.update named_args } -> *ordered_args, **named_args { self.( *o.( *ordered_args ), **n.( **named_args ) ) } end end ``` And then, the usage would be: ```ruby meal = -> main_course, soup, appetizer: nil, dessert: nil, drink: "beer" do { main_course: main_course, soup: soup, appetizer: appetizer, dessert: dessert, drink: drink } end a_la_carte = meal.curry( 1 => "chicken broth", dessert: "creme brule", drink: "mineral water" ) a_la_carte.( "coq au vin" ) #=> {:main_course=>"coq au vin", :soup=>"chicken broth", :appetizer=>nil, :dessert=>"creme brule", :drink=>"mineral water"} a_la_carte.( "coq au vin", dessert: "blueberry cake" ) #=> {:main_course=>"coq au vin", :soup=>"chicken broth", :appetizer=>nil, :dessert=>"blueberry cake", :drink=>"mineral water"} ``` There are some unresolved issues lurking in the above prototype code (such as how to curry methods and what to do with blocks), but since I took the pain to write it, I'm gonna use it in my personal library. But seriously, this is the only form of `#curry` which I can understand and memorize. Current `#curry` with its `n` argument is absolutely awful. Phew. I came out and actually said what I think this time. ---------------------------------------- Feature #7939: Alternative curry function creation https://bugs.ruby-lang.org/issues/7939#change-45352 * Author: Kresimir Bojcic * Status: Assigned * Priority: Normal * Assignee: Yukihiro Matsumoto * Category: core * Target version: next minor ---------------------------------------- =begin I really like the new "(({assuming}))" method used for currying in Perl 6. For example if I loose my mind and implement ((%fizzbuzz%)) via currying I can do it like this: fb = ->(modulo_number, message, x) { message if x % modulo_number == 0 } fizzbuzz = fb.curry[15,"FizzBuzz"] fizz = fb.curry[3, "Fizz"] buzz = fb.curry[5, "Buzz"] (1..100).each { |i| puts fizzbuzz[i] || fizz[i] || buzz[i] || i } Here the first hurdle is that curry is somewhat mathematical, and the secons is that you need to use (({[]})) for function invoking... If we had something similar to this: class Proc def assuming(*args) curry.call *args end end It could be written more naturally IMO: fb = ->(modulo_number, message, x) { message if x % modulo_number == 0 } fizzbuzz = fb.assuming(15,"FizzBuzz") buzz = fb.assuming(5, "Buzz") fizz = fb.assuming(3,"Fizz") (1..100).each { |i| puts fizzbuzz[i] || fizz[i] || buzz[i] || i } =end -- http://bugs.ruby-lang.org/