Мне нужны некоторые примеры реализации функции curry в ruby (1.8.6 или 1.8.7, а не 1.9).Как реализовать curry (частичная функция) в ruby
5
A
ответ
5
Так вот как сделать выделки с блоками, а не методами:
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
И это довольно хорошо работает на практике. Аргументы могут быть кэрри или нет, и дополнительных аргументов собраны как обычно:
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
Я сделал проектное решение иметь без аргументов блоков не возвращают непосредственное значение на выделки:
irb> curry { 3 }
#=> 3
irb> curry { |*xs| xs }
#=> []
Это необходимо, чтобы избежать необходимости заканчивать работу с []
каждый раз (и довольно похож на Haskell).
3
Возможно, это может помочь: http://asemanfar.com/Currying-in-Ruby. Он имеет исходный код для модуля Curriable.