moo-nad-0.1.0.1: lib-example-logic-that-logs/Moo.hsig
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
-- | The logic in this sub-library needs to know how to perform logging,
-- and use a counter
--
-- To allow for that, we expand the signature through signature merging,
-- defining a 'HasLogger' typeclass and demanding that the environment 'E'
-- has an instance.
--
-- We also define a 'Counter' component (basically a record-of-functions polymorphic on
-- the base monad) and tie it to the environment 'E' using the generic Has class from
-- Control.Monad.Dep.Has.
signature Moo where
import Data.Kind
import Control.Monad.Dep.Has
data D :: Type -> Type
data E :: Type
instance HasLogger D E -- this wasn't in the base Moo signature
instance Has Counter D E -- this wasn't, either
-- A typeclass for extracting some capability from an environment.
--
-- Program logic invokes should invoke its method using "Moo.Prelude.self".
--
-- Typeclass definitions are allowed in signatures,
-- methods and all. The corresponding definitions in the implementation
-- modules must match exactly.
--
-- The typeclass could also have been imported from another package.
class HasLogger d e | e -> d where
logger :: e -> Int -> String -> d ()
-- A component is a record-of-functions parameterized by the effect monad
-- used by the functions.
--
-- Components are tied to the environment using the "Control.Monad.Dep.Has.Has" typeclass,
-- and program logic should invoke their functions using "Moo.Prelude.call".
--
-- Datatype definitions are allowed in signatures. The corresponding definitions in
-- the implementation modules must match exactly.
--
-- The datatype could also have been imported from another package.
data Counter d = Counter {
askCounter :: d Int,
incCounter :: Int -> d ()
}