Feature #9548
closed
Module curry
Description
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" )
end
or curry
directive similar to the existing alias
directive
module Foo
curry sym2 sym1( 42, 43, *, 44, foo: "bar )
end
Example usage:
module MyMath
def power a, b
a ** b
end
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, * )
end
Updated by srawlins (Sam Rawlins) over 9 years 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 }) }
end
and one for Methods:
def curry_m(m, n, *args)
define_method(m, curry(method(n), *args))
end
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
Updated by mame (Yusuke Endoh) over 9 years ago
That is not "currying", but "partial application."
http://lambda-the-ultimate.org/node/2266
--
Yusuke Endoh mame@tsg.ne.jp
Updated by Anonymous over 9 years ago
@mame (Yusuke Endoh), 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).
Updated by Anonymous over 9 years 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.
Updated by matz (Yukihiro Matsumoto) over 9 years 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?
Matz.
Updated by Anonymous about 9 years 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
end
# class assets
end
class Net
# class assets
def simulation **named_args
Simulation.new **named_args
end
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.
end
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
.)
Updated by Anonymous about 9 years ago
Having studied up the theory, I have added a feature request that would enable to misuse curry
for partial application, #9620.