使用通用 Persistent 时,PersistStoreWrite (BaseBackend x) 约束从何而来?

Where does PersistStoreWrite (BaseBackend x) constraint come from when using generic Persistent?

在玩弄 persistent 时,我无法弄清楚 PersistStoreWrite (BaseBackend b) 约束从何而来。我在insert.

的签名上看不到
x :: (
    MonadIO m,
    PersistStoreRead b,
    PersistStoreWrite b,
    PersistStoreWrite (BaseBackend b)      -- <--- where does this come from?
    ) => ReaderT b m ()
x = do
    now <- liftIO getCurrentTime
    aTaskId <- insert (TaskItem "Hello" now)
    aTask <- get aTaskId
    liftIO (print aTask)

以上工作正常,但如果我删除提到的约束,编译器会抱怨 ("arising from a use of insert")。 我将堆栈与 lts-7.12 解析器(GHC 8,持久性 2.6)一起使用。

记录的数据定义:

share [mkPersist sqlSettings{mpsGeneric = True}, mkMigrate "migrateAll"] [persistLowerCase|
TaskItem
    name Text
    submittedAt UTCTime
    deriving Show

奇怪的是,get 方法也需要 BaseBackend 写入。正如@snoyman 所暗示的,这部分是由于生成的 TH 代码。部分TH生成的拼接:

instance PersistStore backend =>
         PersistEntity (TaskItemGeneric backend) where
    type PersistEntityBackend (TaskItemGeneric backend) = backend

请注意 PersistStorePersistStoreWrite 的别名。这与 PersistStoreReadget 方法上的约束 PersistRecordBackend record backend 相结合,扩展为:

type PersistRecordBackend record backend =
    (PersistEntity record, PersistEntityBackend record ~ BaseBackend backend) 

确实导致推断约束 PersistStoreWrite (BaseBackend backend)

解决方案

事实上这是微不足道的 - 明智的 BaseBackend 应该始终支持写入。所以我只是为约束添加了别名:

type PersistRead b = (PersistStoreRead b, PersistStoreWrite (BaseBackend b))
type PersistWrite b = (PersistRead b, PersistStoreWrite b)

所以

x :: (MonadIO m, PersistWrite b) => ReaderT b m ()
x = do
    now <- liftIO getCurrentTime
    aTaskId <- insert (TaskItem "Hello" now)
    aTask <- get aTaskId
    liftIO (print aTask)