Following up on this, I have the following typeclasses:
class Monoid m => BuilderS m a where
cstr :: String -> a -> m
class SafeCopy a where
putSafe :: a -> m
Providing instances for BuilderS
:
import qualified Data.Serialize.Builder as B
instance Serialize a => BuilderS B.Builder a where
cstr _ = B.fromByteString . encode
instance BuilderS CustomBuilder Int where
cstr = ...
instance BuilderS CustomBuilder String where
cstr = ...
etc.
I would like to define instances of SafeCopy
like this:
data Person = Person { name :: String, age :: Int }
instance SafeCopy Person where
putSafe p = cstr "name" (name p)
However, in this specific case the compiler can't find an instance of BuilderS m String
. I've tried several things:
putSafe
:
putSafe :: (BuilderS m Int, BuilderS m String, ...) => a -> m
. This works, but is not extensible (i.e. what if I want to have a BuilderS m Vector
constraint in the future?)m
to the type parameters of SafeCopy
.data SumT m = forall a b. (BuilderS m a, BuilderS m b) => a :+: b
and then have putSafe :: a -> SumT m
.Still, I'm not providing enough information to the type system so it can defer the decision of which exact instance of BuilderS
to use for later. What am I missing?
You can do something like this:
class SafeCopy a m where
putSafe :: a -> m
instance BuilderS m String => SafeCopy Person m where
putSafe p = cstr "name" (name p)
You'll need to turn on a lot of language extensions.