Open yuroyoro opened 7 years ago
Proc#compose でProc同士を合成できるようにする。 f.compose g で、 Proc{|x| f.call(g.call(x)) } となるProcを生成する
Proc#compose
f.compose g
Proc{|x| f.call(g.call(x)) }
f = Proc.new{|x| x + 1 } g = Proc.new{|x| x * x } f.compose(g).call(2) #=> 5
雑な実装イメージはこんな感じ
class Proc def compose(f) Proc{|x| self.call(f.to_proc.call(x)) } end end
さらに、 Proc#reverse_compose で 逆の関数合成もできるようにする。 f.reverse_compose(g).call(x) == g.compose(f).call(x) となる。
Proc#reverse_compose
f.reverse_compose(g).call(x) == g.compose(f).call(x)
Proc#>>
Proc#<<
alias_method :<<, :compose と alias_method :>>, :reverse_compose にaliasしておくことで利便性が向上する
alias_method :<<, :compose
alias_method :>>, :reverse_compose
Symbol
Symbol にも compose および reverse_compose を実装する。 実装はself.to_proc.compose するだけ
compose
reverse_compose
self.to_proc.compose
以下のようなコードは、関数合成があればすっきりと記述できる
arr = [:foo, :bar, :baz] # arrをto_sしてupcaseする # blockを書く場合 arr.map{|v| v.to_s.upcase } # mapを2回書く場合 arr.map(&:to_s).map(&:upcase) # composeを使うとこのように書ける arr.map(&:to_s.to_proc.compose(&:upcase)) # さらに、 >> を使うと呼び出しの流れを可視化できる arr.map(&:to_s.to_proc >> :upcase.to_proc) # Symbolに >> が実装されていればさらにすっきりする arr.map(&:to_s >> :upcase)
おーどこかでみたcompositionだ!!!
この辺読んだことあります! http://yuroyoro.hatenablog.com/entry/2012/08/10/232443
はい、この記事と、以前作ったgemをCレベルで実装してみます
実装 : https://github.com/yuroyoro/ruby/pull/7
5年前にどの記法を採用するかで揉めてる…
https://bugs.ruby-lang.org/issues/6284
上記のIssueにcommented.
https://bugs.ruby-lang.org/issues/6284#note-50
概要
Proc#compose
でProc同士を合成できるようにする。f.compose g
で、Proc{|x| f.call(g.call(x)) }
となるProcを生成する雑な実装イメージはこんな感じ
逆方向の関数合成のサポート
さらに、
Proc#reverse_compose
で 逆の関数合成もできるようにする。f.reverse_compose(g).call(x) == g.compose(f).call(x)
となる。Proc#>>
とProc#<<
にaliasするalias_method :<<, :compose
とalias_method :>>, :reverse_compose
にaliasしておくことで利便性が向上するSymbol
への拡張Symbol
にもcompose
およびreverse_compose
を実装する。 実装はself.to_proc.compose
するだけモチベーション
以下のようなコードは、関数合成があればすっきりと記述できる