dep-t-0.6.3.0: lib/Dep/Tagged.hs
{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE StandaloneKindSignatures #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ExplicitForAll #-}
-- | Companion module to "Dep.Has" for disambiguanting record components within an environment.
--
-- Similar in purpose to the [Qualifier annotation](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/annotation/Qualifier.html) in Java Spring.
--
-- >>> :{
-- newtype Foo d = Foo {foo :: String -> d ()} deriving Generic
-- makeIOFoo :: MonadIO m => Foo m
-- makeIOFoo = Foo (liftIO . putStrLn)
-- makeIOFoo' :: MonadIO m => Foo m
-- makeIOFoo' = Foo (\_ -> liftIO $ putStrLn "this is secondary")
-- env :: InductiveEnv '[Foo, Tagged "secondary" Foo] Identity IO
-- env = AddDep @Foo (Identity makeIOFoo)
-- $ AddDep @(Tagged "secondary" Foo) (Identity (tagged makeIOFoo'))
-- $ EmptyEnv
-- :}
--
-- >>> :{
-- foo (dep env) "this is foo"
-- :}
-- this is foo
--
-- >>> :{
-- foo (untag @"secondary" (dep env)) "this is foo"
-- :}
-- this is secondary
--
--
-- When using functions from "Dep.SimpleAdvice" (which tend to depend on coercions) with 'Tagged' components, remember to import the newtype's constructor.
module Dep.Tagged
(
Tagged (..),
tagged,
untag
)
where
import Data.Kind
import Data.Typeable
import GHC.Generics qualified as G
-- | Very similar to the @Data.Tagged@ type from the \"tagged\" package, but
-- with an extra monad type argument. The intended use is to disambiguate
-- record components within an environment, when there are multiple records of the same
-- type.
type Tagged :: k -> ((Type -> Type) -> Type) -> (Type -> Type) -> Type
newtype Tagged s r_ m = Tagged {unTagged :: r_ m}
deriving
(
G.Generic,
Typeable
)
-- When inserting into an environment a component that you want to disambiguate, provide the the tag using a type variable and then supply the record value.
tagged :: forall s r_ m . r_ m -> Tagged s r_ m
tagged = Tagged
-- | Alias for 'unTagged'.
--
-- When invoking a method from a tagged dependency,
-- provide the tag using a type application and compose with the record selector.
untag :: Tagged s r_ m -> r_ m
untag = unTagged
-- $setup
--
-- >>> :set -XTypeApplications
-- >>> :set -XMultiParamTypeClasses
-- >>> :set -XImportQualifiedPost
-- >>> :set -XTemplateHaskell
-- >>> :set -XStandaloneKindSignatures
-- >>> :set -XNamedFieldPuns
-- >>> :set -XFunctionalDependencies
-- >>> :set -XFlexibleContexts
-- >>> :set -XDataKinds
-- >>> :set -XBlockArguments
-- >>> :set -XFlexibleInstances
-- >>> :set -XTypeFamilies
-- >>> :set -XDeriveGeneric
-- >>> :set -XViewPatterns
-- >>> import Data.Kind
-- >>> import Control.Monad.IO.Class
-- >>> import GHC.Generics (Generic)
-- >>> import Dep.Has
-- >>> import Dep.Env
--