Reputation: 588
I am trying to adopt the idea of ReaderT pattern in a simple production system.
In the original example data type Env
is defined as:
data Env = Env
{ envLog :: !(String -> IO ())
, ...
}
I my implementation,
I defined a typeclass Serializable
to help me logging different data types.
So that I could have a more generic logging function (including serialization in different file format):
data Env = Env
{ evnLog :: (Serializable a) => a -> FilePath -> IO ()
, ...
}
Of course, this doesn't work. The error message is:
Not in scope: type variable ‘a’
|
61 | { envLog :: (Serializable a) =>
| ^
If a
is included in the Type constructor of Env
, I will be forced to change the Context information in ReaderT constantly, it would be really cumbersome.
I just want to pass this generic function along a sequences of computations and use it whenever being needed.
Is there any possibility of not introducing a
in the Type constructor of Env
? Or maybe ReaderT pattern needs more tricks to be used like this?
Upvotes: 3
Views: 98
Reputation: 48572
You're trying to use a rank-2 type (specifically, the type of the Env
data constructor). You need to both enable the RankNTypes
extension, and use a forall
since rank-2 types are never inferred:
{-# LANGUAGE RankNTypes #-}
data Env = Env
{ envLog :: forall a. (Serializable a) => a -> FilePath -> IO ()
, ...
}
Upvotes: 7