{-# LANGUAGE PolyKinds     #-}
{-# LANGUAGE RankNTypes    #-}
{-# LANGUAGE TypeOperators #-}

{-# OPTIONS_GHC -Wall -Wno-name-shadowing #-}

module Data.IMonad
    ( IMonad (..)
    -- * Re-exports
    , module Data.IFunctor
    ) where

import           Data.Functor.Sum (Sum (InL, InR))
import           Data.IFunctor    (IFunctor (imap), type (~~>))

class IFunctor f => IMonad f where
    ipure :: a ~~> f a
    ijoin :: f (f a) ~~> f a
    ijoin = (f a ~~> f a) -> f (f a) ~~> f a
forall k (f :: (k -> *) -> k -> *) (a :: k -> *) (b :: k -> *).
IMonad f =>
(a ~~> f b) -> f a ~~> f b
ibind f a ~~> f a
forall a. a -> a
id
    ibind :: (a ~~> f b) -> (f a ~~> f b)
    ibind f :: a ~~> f b
f = f (f b) ix -> f b ix
forall k (f :: (k -> *) -> k -> *) (a :: k -> *).
IMonad f =>
f (f a) ~~> f a
ijoin (f (f b) ix -> f b ix)
-> (f a ix -> f (f b) ix) -> f a ix -> f b ix
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a ~~> f b) -> f a ~~> f (f b)
forall k k (f :: (k -> *) -> k -> *) (a :: k -> *) (b :: k -> *).
IFunctor f =>
(a ~~> b) -> f a ~~> f b
imap a ~~> f b
f
    {-# MINIMAL ipure, (ijoin | ibind) #-}

instance IMonad (Sum a) where
    ipure :: a ix -> Sum a a ix
ipure = a ix -> Sum a a ix
forall k (f :: k -> *) (g :: k -> *) (a :: k). g a -> Sum f g a
InR
    ijoin :: Sum a (Sum a a) ix -> Sum a a ix
ijoin (InL x :: a ix
x) = a ix -> Sum a a ix
forall k (f :: k -> *) (g :: k -> *) (a :: k). f a -> Sum f g a
InL a ix
x
    ijoin (InR x :: Sum a a ix
x) = Sum a a ix
x