Skip to content

Procに関数合成を実装する #13

@yuroyoro

Description

@yuroyoro

概要

Proc#compose でProc同士を合成できるようにする。
f.compose g で、 Proc{|x| f.call(g.call(x)) } となるProcを生成する

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#>>Proc#<< にaliasする

alias_method :<<, :composealias_method :>>, :reverse_compose にaliasしておくことで利便性が向上する

Symbol への拡張

Symbol にも 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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions