module Functional

  def identity
    ->x{ x}
  end


  module ClassMethods

    def compose(*proc_chain)
      proc_chain = proc_chain.first if proc_chain.first.class == Array
      proc_chain.reduce(->(x){x}){|result,p| result.compose(p)}
    end
  end




  def complement
  lambda {|*args| not self.call(*args) }
  end

 def compose(other)
    lambda {|*args| call(other.call(*args)) }
  end

  def pipe(other)
    other.compose(self)
  end


  alias :* :compose
  alias :>> :pipe





end

class Proc; include Functional; extend Functional::ClassMethods; end
class Method; include Functional; extend Functional::ClassMethods; end