跟进这个,我有以下类型类:
class Monoid m => BuilderS m a where
cstr :: String -> a -> m
class SafeCopy a where
putSafe :: a -> m
提供实例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.
我想定义这样的实例SafeCopy
:
data Person = Person { name :: String, age :: Int }
instance SafeCopy Person where
putSafe p = cstr "name" (name p)
但是,在这种特定情况下,编译器找不到BuilderS m String
. 我尝试了几件事:
putSafe
将所有原始数据类型添加到: 的约束中putSafe :: (BuilderS m Int, BuilderS m String, ...) => a -> m
。这可行,但不可扩展(即,如果我想BuilderS m Vector
在将来有一个约束怎么办?)- 添加
m
到类型参数中SafeCopy
。 - 使用自定义总和类型:
data SumT m = forall a b. (BuilderS m a, BuilderS m b) => a :+: b
然后拥有putSafe :: a -> SumT m
.
尽管如此,我没有向类型系统提供足够的信息,因此它可以推迟决定BuilderS
稍后使用哪个确切实例。我错过了什么?