Is there any way to use the Has Field env type class with Records.
The data-has package provides instances for Tuples but I can't seem to figure any way to use it with records without manually providing instances.
I've been looking at the way kowainik approached it in cake-slayer and it seems nice but still requires the manual instances to be generated.
module CakeSlayer.Has
( Has (..)
, grab
-- * Deriving helpers
, Field (..)
) where
import GHC.Records (HasField (getField))
import GHC.TypeLits (Symbol)
class Has field env where
obtain :: env -> field
-- | General function to retrieve fields with 'Has' class.
grab :: forall field env m . (MonadReader env m, Has field env) => m field
grab = asks $ obtain @field
{-# INLINE grab #-}
newtype Field (s :: Symbol) env = Field
{ unField :: env
}
instance forall s f env . (HasField s env f) => Has f (Field s env) where
obtain :: Field s env -> f
obtain = getField @s . unField
{-# INLINE obtain #-}
is there any way where i can do something like the following:
data Env = Env
{ pgEnv :: PG
, rabbitEnv :: Rabbit
... many other fields
} deriving (Has)
runPgStuff :: (MonadReader env m, Has PG env) => m ()
runPgStuff = do
e <- asks pgEnv -- | get pg env
run e query
This would help specifically for testing purposes where i might have a monolithic Env type with 20 fields but the scope of my function under test is only using 2 of those fields. In that case i can do something like:
import MyModule (runPgStuff)
data EnvMock = EnvMock
{ pgEnv :: PG
} deriving (Has)
runReaderT runPgStuff envMock
Maybe i'm going about this in a bad way so any advice on a better approach is appreciated. Another thought i had was defining the manual instances for my monolithic Env type and then using the provided tuple instances in data-has for testing.