Automatically infer multiparameter instance

112 Views Asked by At

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:

  • Add all primitive datatypes to the constraints of 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?)
  • Add m to the type parameters of SafeCopy.
  • Use a custom sum type: 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?

1

There are 1 best solutions below

0
On BEST ANSWER

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.