{-# LANGUAGE DataKinds #-} {-# LANGUAGE StrictData #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE UndecidableInstances #-} module Test.Data.Registry.THSpec where import Data.Generics.Product.Typed import Data.Registry.TH import Protolude import Universum ((...)) -- * Example of TemplateHaskell usage to create the typeclass corresponding to a component -- | We define 2 low-level components: Logger and Tracer -- We make the corresponding typeclasses data Logger m = Logger { -- a function taking 2 arguments _info :: Text -> Text -> m (), -- a function having a constraint _error :: forall a. (Monoid a) => a -> Text -> m () } makeTypeclass ''Logger newtype Tracer m = Tracer { _traceIt :: Text -> m () } makeTypeclass ''Tracer -- | Now we make a component which is going to use both components newtype Service m = Service { doIt :: Int -> Text -> m () } newService :: Monad m => Logger m -> Tracer m -> Service m newService logger tracer = Service { doIt = run ... implementService } where -- the typeclass instances can be resolved by using a Reader containing -- a tuple with all the components run = flip runReaderT (logger, tracer) -- | Implement the service using typeclasses implementService :: Monad m => WithLogger m => WithTracer m => Int -> Text -> m () implementService n t = do info "doing it" t traceIt (show n)