c4se記:さっちゃんですよ☆

.。oO(さっちゃんですよヾ(〃l _ l)ノ゙☆)

.。oO(此のblogは、主に音樂考察Programming に分類されますよ。ヾ(〃l _ l)ノ゙♬♪♡)

音樂は SoundCloud に公開中です。

考察は現在は主に Scrapbox で公表中です。

Programming は GitHub で開發中です。

Rubyで作ったFactorっぽい連鎖性記法が間違ってゐたので直した

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

ここから普通の関数を、省略記法としてつかへるやうにするのは、いいことだとおもふ。