Ruby, Proc#curry
引数全部カリー化したい (一回だけじゃなくて)。可変長引数は考慮しない。
Lambda = Proc
class Lambda
def curry
s = self
args = []
(1...self.arity).inject(lambda {|x| p args; s[*(args+[x])] }) {|r,i|
lambda {|x|
args = args + [x]
r
}
}
end
end
sum = lambda {|x, y, z| x - y + z }.curry
p sum[1][2][3] # 2
p sum[1][2][3] # args が破壊されて失敗なんかいろいろやってみたけどうまくいかないので eval に逃げ
Lambda = Proc
class Lambda
def curry
s = <<-EOS.gsub(/^¥t{3}/, "")
lambda {|al|
args = [#{(1...self.arity).inject(""){|r,i|r<<"a#{i}, "}}al]
ObjectSpace._id2ref(#{self.object_id})[*args]
}
EOS
eval (1...self.arity).inject(s) {|r,i|
<<-EOS.gsub(/^¥t{4}/, "")
lambda {|a#{self.arity-1-i+1}|
#{r}
}
EOS
}
end
end
sum = lambda {|x, y, z| x - y + z }.curry
p sum[1][2][3] # 2
p (sum1 = sum[1])
p sum1[2][3]
p lambda {|x, y, z, a| x + y + z + a}.curry[1][2][3][4]
これ GC で死ぬよね。参照保持しないと
もっと簡単に書けた。あと ObjectSpace._id2ref は $SAFE 高いとつかえない。
class Lambda
def curry
s = <<-EOS.gsub(/^\t{3}/, "")
lambda {|al|
args = [#{(1...self.arity).inject(""){|r,i|r<<"a#{i}, "}}al]
self[*args]
}
EOS
instance_eval (1...self.arity).inject(s) {|r,i|
<<-EOS.gsub(/^\t{4}/, "")
lambda {|a#{self.arity-1-i+1}|
#{r}
}
EOS
}
end
end