0

跟进这个,我有以下类型类:

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稍后使用哪个确切实例。我错过了什么?

4

1 回答 1

1

你可以这样做:

class SafeCopy a m where
  putSafe :: a -> m

instance BuilderS m String => SafeCopy Person m where
  putSafe p = cstr "name" (name p)

您需要打开很多语言扩展。

于 2014-08-28T12:32:45.037 回答