/-
Copyright (c) 2016 Gabriel Ebner. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Gabriel Ebner
-/
namespace monad

class monad_transformer (transformer : ∀m [monad m], Type → Type) :=
(is_monad : ∀m [monad m], monad (transformer m))
(monad_lift : ∀m [monad m] α, m α → transformer m α)

instance transformed_monad (m t) [monad_transformer t] [monad m] : monad (t m) :=
monad_transformer.is_monad t m

class has_monad_lift (m n : Type → Type) :=
(monad_lift : ∀α, m α → n α)

instance monad_transformer_lift (t m) [monad_transformer t] [monad m] : has_monad_lift m (t m) :=
⟨monad_transformer.monad_lift t m⟩

class has_monad_lift_t (m n : Type → Type) :=
(monad_lift : ∀α, m α → n α)

def monad_lift {m n} [has_monad_lift_t m n] {α} : m α → n α :=
has_monad_lift_t.monad_lift n α

prefix `♯ `:0 := monad_lift

instance has_monad_lift_t_trans (m n o) [has_monad_lift n o] [has_monad_lift_t m n] : has_monad_lift_t m o :=
⟨ λα (ma : m α), has_monad_lift.monad_lift o α $ has_monad_lift_t.monad_lift n α ma ⟩

instance has_monad_lift_t_refl (m) [monad m] : has_monad_lift_t m m :=
⟨ λα, id ⟩

end monad

namespace state_t

def state_t_monad_lift (S) (m) [monad m] (α) (f : m α) : state_t S m α :=
take state, do res ← f, return (res, state)

instance (S) : monad.monad_transformer (state_t S) :=
⟨ state_t.monad S, state_t_monad_lift S ⟩

end state_t
