Rubyでflip

関数合成できた。ポイントフリーができた。カリー化もある。
なら次はflipで部分適応の順序を入れかえてやりたい。
まずは下記のProc#flipを見て試す。
http://yuroyoro.hatenablog.com/entry/2012/08/10/232443

div = lambda{|x,y| x.to_f / y }
div.(10,2)
#=> 5.0
div.flip.(10,2)
#=> 0.2

確かにできてる。でも3つ引数をとる場合、第2引数と第3引数を部分適応することはできないらしい。
やってみる。

  f = ->a,b,s { s.to_s.gsub(a, b) }
  p f.(/oo/,"aa","foooo")
  #=> "faaaa"
  p f.flip.("aa", /oo/,"foooo")
  #=> "faaaa"
  p f.flip.curry.("aa").flip.("foooo").(/oo/)
  #=> "(?-mix:oo)" わけのわからん物が返ってきた。

確かに一度カリー化されたProcに対してflipしても効果がない。当然だけど…
でもあきらめちゃだめだ。
上記のアプローチはカリー化されてないものに対してのflipしかない
ならカリー化されてるものに対してのflipを書けばいい。
実装は以下

def flip
  ->f, x, y { f[y][x] }.curry
end

このflipを使って第2引数と第3引数を先に部分適応できる形に変換してやるとこうなる

  f1 = (flip << flip.(f.curry))
  p f1.("aa").("foooo").(/oo/) #元の呼び出しはこう⇒ f.(/oo/,"aa","foooo")
  #=> "faaaa"

変換の途中経過は以下

  # 第1引数と第2引数をひっくり返す
  p flip.(f.curry).("aa").(/oo/).("foooo")
  #=> "faaaa"
  # 元の第1引数と第3引数をひっくり返す
  # つまりひとつ前の第2引数と第3引数をひっくり返す
  p flip.(flip.(f.curry).("aa")).("foooo").(/oo/)
  #=> "faaaa"
  # 最後に関数合成をして元の第2引数を外に追いやる
  # ひとつ前で関数の中に埋ってる"aa"を追いやる
  f1 = (flip << flip.(f.curry))
  p f1.("aa").("foooo").(/oo/) #元の呼び出しはこう⇒ f.(/oo/,"aa","foooo")
  #=> "faaaa"

カリー化されてるProcに対してもflipできた。