RubyでFactorっぽい連鎖性 concatenative (関数合成) 記法を作るが完璧に間違へてゐたので直した。実際は此れは関数合成に成ってゐない。ループして順に評価してゐるだけだ。此れはconcatenativeではない。Factorでは全てのwordはいちおう、暗黙のstackを受け取り暗黙のstackを返す関数である。ところが前記事には、いろいろ引数をとり値をちゃんと返す関数と、stack効果関数とが混在してゐる。記法の方便としてではなく、本質的に混在してゐる。それがあの醜さだ。
ちゃんと全てstack効果関数とし、合成した。
# coding=utf-8 # license: Public Domain # Rubyでcurry化しない関数合成 http://c4se.hatenablog.com/entry/2014/07/27/140057 def compose *fs; proc{|*args| fs.inject(args){|args, f| f.call *args } }; end class Factor def initialize @stack = [] @definitions = {} end def pop n = 1; n == 1 ? @stack.pop : @stack.pop(n); end def call *words compose(*words.map do |word| if word.class.method_defined? :call proc{ word.call self; self } elsif word.is_a? Symbol proc{ @stack << (@definitions[word] || word); self } else proc{ @stack << word; self; } end end).call self end def local names, words names.reverse.map{|name| proc{ let name, pop } } + words + names.map{|name| proc{ unlet name } } end private def let name, word; @definitions[name] = word; end def unlet name; @definitions.delete name; end end dup = ->(ctx){ v = ctx.pop; ctx.call v, v } swap = ->(ctx){ u, v = ctx.pop 2; ctx.call v, u } drop = ->(ctx){ ctx.pop } call = ->(ctx){ ctx.call *ctx.pop } times = ->(ctx){ n, words = ctx.pop 2; n.times{ ctx.call *words } } if_ = ->(ctx){ bool, then_words, else_words = ctx.pop 3; bool ? ctx.call(*then_words) : ctx.call(*else_words) } print = ->(ctx){ Kernel.print ctx.pop } append = ->(ctx){ s1, s2 = ctx.pop 2; ctx.call "#{s1}#{s2}" } to_s = ->(ctx){ ctx.call ctx.pop.to_s } sub = ->(ctx){ n, m = ctx.pop 2; ctx.call(n - m) } prod = ->(ctx){ ctx.call(ctx.pop * ctx.pop) } is_eq = ->(ctx){ ctx.call(ctx.pop == ctx.pop) } is_lt = ->(ctx){ u, v = ctx.pop 2; ctx.call(u < v) } Factor.new. call("Hello world", print). call(10, ["Hello, Factor", print], times). call("Hello, ", "Factor", append, print) # Factor で階乗。然して再帰に就いて抄 http://c4se.hatenablog.com/entry/2013/12/30/030205 factorial_rec = -> ctx do ctx.call dup, 0, is_eq, [drop], [ ctx.local([:n, :m], [:n, :m, prod, :m, 1, sub, factorial_rec]), call ], if_ end factorial = -> ctx do ctx.call dup, 0, is_lt, [drop, 0], [1, swap, factorial_rec], if_ end Factor.new.call "\n", 10, factorial, to_s, append, print
ここから普通の関数を、省略記法としてつかへるやうにするのは、いいことだとおもふ。