9 October 2007 Norbert Crombach and Manfred Stienstra

This episode shows some syntactic improvements on the Function Composition code we demonstrated in the first video of the series.

Download episode

# Contains code by Eric Kidd, Peter Burns, and Ola Bini

class Object
  def op(c)
    lambda { |x| eval(c) }
  end
end

class Proc
  class << self
    def complement(f = nil, &b)
      b ||= f
      lambda { |*a| !b.call(*a) }
    end

    def compose(*a)
      a.map! { |b| b.to_proc }
      
      if a.length == 2
        lambda { |*args| a[0].call(a[1].call(*args)) }
      elsif a.length > 2
        compose(a.shift, compose(*a))
      else
        lambda { nil }
      end
    end

    def conjoin(*a)
      lambda { |*args| a.all? { |f| f.call(*args) } }
    end

    def disjoin(*a)
      lambda { |*args| a.any? { |f| f.call(*args) } }
    end
  end

  def complement
    self.class.complement(self)
  end

  def compose(*a)
    self.class.compose(*(a.reverse + [self]))
  end
  
  def conjoin(*a)
    self.class.conjoin(*([self] + a))
  end
  
  def disjoin(*a)
    self.class.disjoin(*([self] + a))
  end

  alias_method :c, :complement
  alias_method :*, :compose
  alias_method :&, :conjoin
  alias_method :|, :disjoin

  alias_method :[], :call
end