how to implement curry(partial function) in ruby
So here's how to do currying with blocks, rather than methods:
def curry(&block)
arity = (block.arity >= 0) ? block.arity : -(block.arity + 1)
# return an immediate value if the block has one
return block[] if arity == 0
# otherwise, curry it argument by argument
args = []
innermost = lambda do |last,*extra|
args[arity-1] = last
block[*(args+extra)]
end
(0...(arity-1)).to_a.reverse.inject(innermost) do |inner,i|
lambda do |arg_i,*extra|
args[i] = arg_i
# pass extra arguments on to inner calls
if extra.empty?
inner
else
inner[*extra]
end
end
end
end
And it works fairly well in practice. Arguments can be curried or not, andextra arguments are collected as usual:
irb> (curry { |x,y| x + y })[1,2]
#=> 3
irb> (curry { |x,y| x + y })[1][2]
#=> 3
irb> (curry { |x,*ys| ys << x })[1]
#=> [1]
irb> (curry { |x,*ys| ys << x })[1,2,3]
#=> [2, 3, 1]
irb> (curry { |x,y,*zs| zs << (x+y) })[1,2]
#=> [3]
irb> (curry { |x,y,*zs| zs << (x+y) })[1,2,4]
#=> [4, 3]
irb> (curry { |x,y,*zs| zs << (x+y) })[1][2]
#=> [3]
irb> (curry { |x,y,*zs| zs << (x+y) })[1][2,4]
#=> [4, 3]
irb> (curry { |a,b,c,d,e| a+b+c+d+e })[1,2,3,4,5]
#=> 15
irb> (curry { |a,b,c,d,e| a+b+c+d+e })[1][2][3][4][5]
#=> 15
irb> (curry { |a,b,c,d,e| a+b+c+d+e })[1,2][3][4][5]
#=> 15
irb> (curry { |a,b,c,d,e| a+b+c+d+e })[1][2,3,4][5]
#=> 15
I made the design decision to have no-arg blocks return an immediate value on currying:irb> curry { 3 }
#=> 3
irb> curry { |*xs| xs }
#=> []
This is necessary to avoid having to end currying with a []
every time (and is fairly Haskell-like). Ruby: provide an argument while turning proc to a block
Regarding your comment:
Actually, the argument order is preserved.Strange, but it swaps arguments during the performance
curry
returns a new proc that effectively collects arguments until there are enough arguments to invoke the original method / proc (based on its arity). This is achieved by returning intermediate procs:
def foo(a, b, c)
{ a: a, b: b, c: c }
end
curried_proc = foo.curry #=> #<Proc:0x007fd09b84e018 (lambda)>
curried_proc[1] #=> #<Proc:0x007fd09b83e320 (lambda)>
curried_proc[1][2] #=> #<Proc:0x007fd09b82cfd0 (lambda)>
curried_proc[1][2][3] #=> {:a=>1, :b=>2, :c=>3}
You can pass any number of arguments at once to a curried proc:curried_proc[1][2][3] #=> {:a=>1, :b=>2, :c=>3}
curried_proc[1, 2][3] #=> {:a=>1, :b=>2, :c=>3}
curried_proc[1][2, 3] #=> {:a=>1, :b=>2, :c=>3}
curried_proc[1, 2, 3] #=> {:a=>1, :b=>2, :c=>3}
Empty arguments are ignored:curried_proc[1][][2][][3] #=> {:a=>1, :b=>2, :c=>3}
However, you obviously can't alter the argument order.An alternative to currying is partial application which returns a new proc with lower arity by fixing one or more arguments. Unlike
curry
, there's no built-in method for partial application, but you can easily write your own:my_proc = -> (arg, num) { arg * num }
def fix_first(proc, arg)
-> (*args) { proc[arg, *args] }
end
fixed_proc = fix_first(my_proc, 'foo') #=> #<Proc:0x007fa31c2070d0 (lambda)>
fixed_proc[2] #=> "foofoo"
fixed_proc[3] #=> "foofoofoo"
[2, 3].map(&fixed_proc) #=> ["foofoo", "foofoofoo"]
Or fixing the last argument:def fix_last(proc, arg)
-> (*args) { proc[*args, arg] }
end
fixed_proc = fix_last(my_proc, 2) #=> #<Proc:0x007fa31c2070d0 (lambda)>
fixed_proc['foo'] #=> "foofoo"
fixed_proc['bar'] #=> "barbar"
['foo', 'bar'].map(&fixed_proc) #=> ["foofoo", "barbar"]
Of course, you are not limited to fixing single arguments. You could for example return a proc that takes an array and converts it to an argument list:
def splat_args(proc)
-> (array) { proc[*array] }
end
splatting_proc = splat_args(my_proc)
[['foo', 1], ['bar', 2], ['baz', 3]].map(&splatting_proc)
#=> ["foo", "barbar", "bazbazbaz"]
Haskell, is it possible to create a curry function that can curry any number of tuple elements
One of the ways to implement such function is to use GHC.Generics. With this approach we don't even need to pass a number of parameters (or tuple size).
This works because there is an instance of Generic
defined for tuples which effectively converts a tuple into tree structure (of type Rep a
) which we can then traverse from right to left (using continuation passing style here) generating curried function along the way and packing the values of those parameters into identical Rep a
structure which then converted into tuple with to
function and passed to the original un-curried function-parameter. This code uses only type-level tree of parameters (from
function is not used) since we produce the tuple rather then receiving it.
The only limitation of this approach is that Generic
is defined only for up to eight-element tuple.
{-# LANGUAGE TypeOperators, MultiParamTypeClasses,
FlexibleInstances, UndecidableInstances,
TypeFamilies, ScopedTypeVariables #-}
import GHC.Generics
-- | class for `curryN` function
class CurryN t r where
type CurriedN t r :: *
curryN :: (t -> r) -> CurriedN t r
-- | Implementation of curryN which uses GHC.Generics
instance (Generic t, GCurryN (Rep t) r) => CurryN t r where
type CurriedN t r = GCurriedN (Rep t) r
curryN f = gcurryN (f . to)
-- | Auxiliary class for generic implementation of `curryN`
-- Generic representation of a tuple is a tree of its elements
-- wrapped into tuple constructor representation
-- We need to fold this tree constructing a curried function
-- with parameters corresponding to every elements of the tuple
class GCurryN f r where
type GCurriedN f r :: *
gcurryN :: (f p -> r) -> GCurriedN f r
-- | This matches tuple definition
-- Here we extract tree of tuple parameters and use other instances to "fold" it into function
instance (GCurryN f r) => GCurryN (D1 e1 (C1 e2 f)) r where
type GCurriedN (D1 e1 (C1 e2 f)) r = GCurriedN f r
gcurryN c = gcurryN (\t -> c (M1 (M1 t)))
-- | A node of the tree (combines at least two parameters of the tuple)
instance (GCurryN b r, GCurryN a (GCurriedN b r)) => GCurryN (a :*: b) r where
type GCurriedN (a :*: b) r = GCurriedN a (GCurriedN b r)
gcurryN c = gcurryN (\a -> gcurryN (\b -> c (a :*: b)))
-- | A leaf of the tree (a single tuple parameter)
instance GCurryN (S1 NoSelector (Rec0 a)) r where
type GCurriedN (S1 NoSelector (Rec0 a)) r = a -> r
gcurryN c = \a -> c $ M1 (K1 a)
-- Examples of usage
t2 = curryN (uncurry (&&))
t3 = curryN (\(a,b,c) -> a + b + c)
t4 = curryN (\(a,b,c,d) -> ((a , b) , (c , d)))
tf = curryN (\(f,a,xs) -> foldr f a xs)
t5 = curryN (\(a,b,c,d,e) -> (a ++ b , c - d, not e))
t7 = curryN (\(a1,a2,a3,a4,a5,a6,a7) -> a7)
What is 'Currying'?
Currying is when you break down a function that takes multiple arguments into a series of functions that each take only one argument. Here's an example in JavaScript:
function add (a, b) {
return a + b;
}
add(3, 4); // returns 7
This is a function that takes two arguments, a and b, and returns their sum. We will now curry this function:function add (a) {
return function (b) {
return a + b;
}
}
This is a function that takes one argument, a
, and returns a function that takes another argument, b
, and that function returns their sum.add(3)(4); // returns 7
var add3 = add(3); // returns a function
add3(4); // returns 7
- The first statement returns 7, like the
add(3, 4)
statement. - The second statement defines a new function called
add3
that will
add 3 to its argument. (This is what some may call a closure.) - The third statement uses the
add3
operation to add 3 to 4, again
producing 7 as a result.
Can we use keyword arguments and curry until all arguments are received?
I came with a small script for my personal use.
PS: If anyone knows a library that can do something similar, please let me know.
import inspect
def curry(function):
original_func = function
original_args = inspect.signature(function).parameters
def wrapper(**kwargs):
call = True
current_args = {}
for each in original_args:
if kwargs.get(each):
current_args[each] = kwargs.get(each)
else:
call = False
if call:
original_func(**current_args)
else:
def partial(**nargs):
current_args.update(nargs)
return wrapper(**current_args)
return partial
return wrapper
@curry
def foo(a=None, b=None, c=None):
print(a, b, c)
# first partial
bar_with_a = bar(a=1)
# next partial
bar_with_a_and_b = bar_with_a(b=1)
# next partial
bar_with_a_and_b = bar_with_a_and_b(b=2)
# next partial
bar_with_a_and_b = bar_with_a_and_b(a=2)
# call
bar_with_a_and_b(c=2)
Related Topics
Starting with Redmine Locally - How Easy Is Migration to Server Later
Converting Ruby Hashes to Arrays
How to Find Word with The Greatest Number of Repeated Letters
Why Do Ruby People Say They Don't Need Interfaces
How to Pick The Method to Call When There Is Mixin Method Name Conflict
How to Make Http Delete Request in My Ruby Code Using Net::Http
How to Test (Rspec) a Http Request That Takes Too Long
How to Run Capybara-Webkit (I.E. Forked Webkit_Server) on Heroku Cedar
List Array of Days Between Two Dates
Can't Get Paypal Encrypted Website Payments to Work in Rails
Calling Module Method into Another Module in Ruby
Server Sent Events and Rails Streaming
How to Remove Header and Footer from Some of The Pages in Ruby on Rails
Ruby: Class C Includes Module M; Including Module N in M Does Not Affect C. What Gives