packages feed

impl-0.2.0.0: example/Monad/Impl.hs

{-# language UndecidableInstances #-} -- Only needed for ++ idiom
module Monad.Impl (module X) where
import Data.Maybe
import Impl as X
import Control.Monad.Fail
import GHC.Err

instance Impl Functor where
  type Methods Functor = [Required "fmap", Optional "constMap"]
  impl f (arg #fmap -> fmap) (Arg' constMap') = case constMap' of
    Nothing -> [d|instance Functor $f where fmap = $fmap|]
    Just constMap -> [d|instance Functor $f where fmap = $fmap;(<$) = $constMap|]

instance Impl Applicative where
  type Methods Applicative = '[Required "pure", Required "ap"] ++ Methods Functor
  impl f (arg #pure -> pure) (arg #ap -> ap) fmap constMap
    = concat <$> sequence
    [impl @Functor f fmap constMap
    ,[d|instance Applicative $f where
          pure = $pure
          (<*>) = $ap |]
    ]

instance Impl Monad where
  type Methods Monad = '[Required "return",Required "bind", Optional "fail", Optional "fmap", Optional "constMap"]
  impl m (arg  #return -> return)
         (arg  #bind -> bind)
         (arg' #fail [|errorWithoutStackTrace|] -> fail)
         (Arg' fmap')
         constMap'
    = concat <$> sequence
    [impl @Applicative m
            $$ #pure return
            $$ #ap [|\mf ma -> $bind mf $ \f -> $bind ma $ \a -> $return (f a) |]
            $$ #fmap (fromMaybe [|\f ma -> $bind ma $ \a -> $return (f a)|] fmap')
            $  constMap'
    ,[d|instance Monad $m where
          return = $return
          (>>=) = $bind
          fail = $fail |]
    ]