Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to implement curry(partial function) in ruby

Tags:

ruby

currying

I need some examples of implementing curry function in ruby(1.8.6 or 1.8.7 not 1.9).

like image 292
Subba Rao Avatar asked Jul 07 '09 21:07

Subba Rao


People also ask

Is partial application the same as currying?

Simple answer. Currying: Lets you call a function, splitting it in multiple calls, providing one argument per-call. Partial Application: Lets you call a function, splitting it in multiple calls, providing multiple arguments per-call.

What is currying in Ruby?

According to Wikipedia, "currying is the technique of transforming a function that takes multiple arguments ... in such a way that it can be called as a chain of functions, each with a single argument."

How does partial application function work?

Partial Application: The process of applying a function to some of its arguments. The partially applied function gets returned for later use. In other words, a function that takes a function with multiple parameters and returns a function with fewer parameters.

Does C# support partial function applications?

Can someone help? There is no partial application in C#: all arguments to a function call must be specified. However, a "wrapping function" (that calls the original function) can be created which can emulate such..


1 Answers

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, and extra 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).

like image 185
rampion Avatar answered Sep 29 '22 06:09

rampion