Monads in Agda -------------- We define them ourselves as follows. Firstly, in the following file \begin{code} open import Agda-in-a-Hurry \end{code} we define a type Type of "small types" by Type = Set This type is "large". \begin{code} LargeType = Set₁ \end{code} We have that Type : LargeType We don't have Type : Type, which would give a contradiction, similar to Russell's paradox (https://en.wikipedia.org/wiki/Russell%27s_paradox). In Haskell the type class of monads is defined by `return` and `>>=` (pronounced bind), and return and bind are required to satisfy some equations. See our adopted book or this link: https://wiki.haskell.org/Monad_laws. In Agda we can write down these equations in the definition of monad: \begin{code} record Monad (M : Type → Type) : LargeType where constructor makeMonad field return : {X : Type} → X → M X _>>=_ : {X Y : Type} → M X → (X → M Y) → M Y requirement₀ : {X Y : Type} (x : X) (f : X → M Y) → (return x >>= f) ≡ f x requirement₁ : {X : Type} (m : M X) → (m >>= return) ≡ m requirement₂ : {X Y Z : Type} (m : M _) (f : X → M Y) (g : Y → M Z) → ((m >>= f) >>= g) ≡ (m >>= (λ x → f x >>= g)) \end{code} Requirements 0 and 1 are known as the unit laws, and requirement 2 is known as the associativity law. Example: Not only we define "return" and "_>>=_", but also we show that they satisfy the requirements: \begin{code} Maybe-Monad : Monad Maybe Maybe-Monad = makeMonad return _>>=_ requirement₀ requirement₁ requirement₂ where return : {X : Type} → X → Maybe X return = Just _>>=_ : {X Y : Type} → Maybe X → (X → Maybe Y) → Maybe Y Nothing >>= f = Nothing Just x >>= f = f x requirement₀ : {X Y : Type} (x : X) (f : X → Maybe Y) → (return x >>= f) ≡ f x requirement₀ x f = refl (f x) requirement₁ : {X : Type} (m : Maybe X) → (m >>= return) ≡ m requirement₁ Nothing = refl Nothing requirement₁ (Just x) = refl (Just x) requirement₂ : {X Y Z : Type} (m : Maybe X) (f : X → Maybe Y) (g : Y → Maybe Z) → ((m >>= f) >>= g) ≡ (m >>= (λ x → f x >>= g)) requirement₂ Nothing g f = refl Nothing requirement₂ (Just x) g f = refl (g x >>= f) \end{code} For the list monad we need list induction to prove the requirements: \begin{code} List-Monad : Monad List List-Monad = makeMonad return _>>=_ requirement₀ requirement₁ requirement₂ where return : {X : Type} → X → List X return = singleton _>>=_ : {X Y : Type} → List X → (X → List Y) → List Y [] >>= f = [] (x ∷ xs) >>= f = f x ++ (xs >>= f) requirement₀ : {X Y : Type} (x : X) (f : X → List Y) → (return x >>= f) ≡ f x requirement₀ x f = []-right-neutral (f x) requirement₁ : {X : Type} (m : List X) → (m >>= return) ≡ m requirement₁ [] = refl [] requirement₁ (x ∷ xs) = ap (cons x) (requirement₁ xs) requirement₂ : {X Y Z : Type} (xs : List X) (f : X → List Y) (g : Y → List Z) → ((xs >>= f) >>= g) ≡ (xs >>= (λ x → f x >>= g)) requirement₂ = ? \end{code} *Bounty.*. The proof of requirement₂ is more difficult, and we leave it is as a challenge for the interested students. It is by induction on lists, using the fact that list concatenation is associative.