Feature #9548

Module curry

Added by Anonymous over 1 year ago. Updated over 1 year ago.



I would like to beg for either Module#curry method with syntax

module Foo
  curry( :sym2, :sym1, 0 => 42, 1 => 43, 3 => 44, foo: "bar" )

or curry directive similar to the existing alias directive

module Foo
  curry sym2 sym1( 42, 43, *, 44, foo: "bar )

Example usage:

module MyMath
  def power a, b
    a ** b

  curry square power( *, 2 )
  curry square_root power( *, 0.5 )
  curry cube( *, 3 )
  curry pow2 power( 2, * )
  curry pow_e power( Math::E, * )
  curry pow10 power( 10, * )


#1 Updated by Sam Rawlins over 1 year ago

Firstly, Proc has a #curry, though not as flexible as you would like: http://rubydoc.info/stdlib/core/Proc#curry-instance_method

Secondly, to implement such flexibility is not too hard in pure Ruby. Here is an implementation of arbitrary currying for Procs:

def curry(prc, *args)
  Proc.new { |*remaining| prc.call(*args.map { |arg| arg || remaining.shift }) }

and one for Methods:

def curry_m(m, n, *args)
  define_method(m, curry(method(n), *args))

Thusly, you can do:

power = ->(a,b){ "#{a}**#{b} is #{a**b}" }
square = curry power, nil, 2
pow2   = curry power, 2, nil

puts "3 squared is #{square.call(3)}"  #=> 3 squared is 9
puts "two to the 3 is #{pow2.call(3)}" #=> two to the 3 is 8

list = ->(a,b,c,d) { "#{a}, #{b}, #{c}, #{d}" }
static_a   = curry list, :hi, nil, nil, nil
static_b_c = curry list, nil, :sam, :adam, nil

puts "static_a: #{static_a.call(:b, :c, :d)}" #=> static_a: hi, b, c, d
puts "static_b_c: #{static_b_c.call(:a, :d)}" #=> static_b,c: a, sam, adam, d

def power_m(a,b); a**b; end
curry_m(:square_m, :power_m, nil, 2)
curry_m(:pow2_m, :power_m, 2, nil)

puts "3 squared is #{square_m(3)}"  #=> 3 squared is 9
puts "two to the 3 is #{pow2_m(3)}" #=> two to the 3 is 8

gist: https://gist.github.com/srawlins/9146528

#2 Updated by Yusuke Endoh over 1 year ago

That is not "currying", but "partial application."


Yusuke Endoh mame@tsg.ne.jp

#3 Updated by Anonymous over 1 year ago

@mame, I don't quite get these nuances between "currying" and "partial application". I could try and
learn them, but my approach is different here. I do not want to learn. I want to be stubborn like
Amazonians when first confronted with Bible. Pragmatically, partial application is all I need. And
since it's long, so let the word be curry. Whole point of using this hunger evoking word (Anglosaxon
surnames notwithstanding) is because it's short and unique, like "quark". And, a shameful secret,
my mnemonic for curry is, oh, it's like with food, there is something (mutton, chicken, veggies...),
and you can add different types of curry to it. And #curry decides about curry, and I then decide
about something. So it's "partial application". I suggest to cannibalize the theorists and settle
for this naïve interpretation of curry. (Just in case that I am really missing something here,
the theorists can go find a different word for that something after we steal curry from them and
use it for "partial application".)

@sam, see #7939 for my take on what Proc#curry should do. Your example implementation
precludes the use of falsey values for currying (in the naïve sense of the word).

#4 Updated by Anonymous over 1 year ago

I have just learned about the existence of Method#parameters method, which would enable to write near-perfect Module#curry without asking for core-level syntax on par with alias. The supporting facts for this feature request are thus slightly weaker than I thought when writing it.

#5 Updated by Yukihiro Matsumoto over 1 year ago

  • Status changed from Open to Feedback

I don't think the term 'curry' is a proper name for the sought behavior.
In addition, I cannot think of a use-case for the feature.
Any concrete example?


#6 Updated by Anonymous over 1 year ago

Indeed, there is much less use for currying than for chaining in the functional world. (In #9552, I now prefer #chain to #map!.) Yet there is already Proc#curry in Ruby (whose present behavior is horrible, imo), therefore it is fair to consider giving the same convenience to the functions employed in modules as methods.

As for the name, in this particular case, I would still argue in favor of Module#curry. My list of imagined possibilities:

#curry --- 5
#partial_application --- 1 --- too long
#partial_apply --- 1
#partially_apply --- 0
#partial --- 2
#filter --- 0 --- means too many things

Should it be decided that this feature on Module is desirable at all, I would like to pretty please you to give your nod to misuse the word curry for it.

As for the usecases, again, there are less of them than for chaining, but let me make up some real-world example which would be of use in my code:

  class Simulation
    def initialize( initial_marking: {},
                    marking_clamps: {},
                    method: :pseudo_euler,
                    step: 1.0,
                    target_time: 60.0,
                    sampling: 5.0,
                    guarded: false )
      # object initialization

    # class assets

  class Net
    # class assets

    def simulation **named_args
      Simulation.new **named_args

    curry euler simulation( method: :euler, ** )
    curry pseudo_euler simulation( method: :pseudo_euler, ** )
    curry runge_kutta simulation( method: :runge_kutta, ** )
    curry gillespie simulation( method: :gillespie, step: nil, ** )
    # Gillespie method computes its own step length.

net = Net.new

# And then, instead of
sim = net.simulation( method: :gillespie,
                      initial_marking: { A: 100, B: 200 },
                      # etc.

# one could just type
sim = net.gillespie( initial_marking: { A: 100, B: 200 },
                     # etc.

So my mnemonic is, here we have simulation with curry named "euler", and then another one with curry named "runge_kutta", etc. (Note that I have simplified the above example, in the real code, Net instances own each a parametrized subclass of Simulation.)

#7 Updated by Anonymous over 1 year ago

Having studied up the theory, I have added a feature request that would enable to misuse curry for partial application, #9620.

Also available in: Atom PDF