class Array
  def bind(f)
    flat_map(&f)
  end
  def self.unit(*args)
    args
  end
  
  
  def self.lift(f)
    -> e { self.unit(f[e]) }
  end
end

inc = -> n { n + 1 }
str = -> n { n.to_s }
listy_inc = Array.lift(inc)
listy_str = Array.lift(str)

Array.unit(3,4,5).bind(listy_inc).bind(listy_str) 






doub = -> n { 2*n }
listy_doub = Array.lift(doub)
[3,4,5].bind(listy_inc).bind(listy_doub) 



comp = -> f, g {-> x {f[g[x]]}}
[3,4,5].bind(comp[listy_doub, listy_inc]) 


class Array
  def bind_comp(f, g)
    bind(g).bind(f)
  end
end

[3,4,5].bind_comp(listy_doub, listy_inc)