{-# OPTIONS --without-K --safe #-}

module Prelude.Monad where

open import Agda.Builtin.Bool

open import Prelude.Level
open import Prelude.Function

open import Prelude.Functor
open import Prelude.Applicative
open import Prelude.List

private variable
  A B : Set _

record Monad (M :  {}  Set   Set ) : Setω where
  infixr 0 caseM_of_
  infixr 1 _=<<_
  infixl 1 _>>=_ _>>_
  field
    _>>=_ : M A  (A  M B)  M B
    overlap  super  : Applicative M

  _>>_ : M A  M B  M B
  m₁ >> m₂ = m₁ >>= λ _  m₂

  _=<<_ : (A  M B)  M A  M B
  _=<<_ = flip _>>=_

  return = pure
  join : {A : Set }  M (M A)  M A
  join = _=<<_ id

  caseM_of_ = _>>=_

  ifM_then_else_ : M Bool  M A  M A  M A
  ifM mb then mx else my = caseM mb of λ where
    true   mx
    false  my

  mapM : (A  M B)  List A  M (List B)
  mapM f []       = return []
  mapM f (x  xs) =  f x  mapM f xs 

  forM : List A  (A  M B)  M (List B)
  forM = flip mapM

open Monad ⦃...⦄ public

{-# DISPLAY Monad._>>=_  _ = _>>=_  #-}
{-# DISPLAY Monad._=<<_  _ = _=<<_  #-}
{-# DISPLAY Monad._>>_   _ = _>>_   #-}

monadAp : {M :  {}  Set   Set }  _ : Functor M 
   (M (A  B)  ((A  B)  M B)  M B)
   M (A  B)  M A  M B
monadAp _>>=_ mf mx = mf >>= λ f  fmap f mx