不能将等式约束表示为自定义约束

Cannot represent equality constraint as a custom constraint

我有一个函数类型声明

f :: MonadHandler m => SqlPersistT m ()

我想转换成

f :: MonadHandlerDB m => m ()

我尝试了所有我能想到的方法来定义约束 MonadHandlerDB,但无法得到它或函数类型声明来编译,例如:

class (forall a . (MonadHandler m, m ~ SqlPersistT a)) => MonadHandlerDB m

class MonadHandlerDB m
instance MonadHandler a => MonadHandlerDB (SqlPersistT a)

type MonadHandlerDB m = forall a . (MonadHandler a, m ~ SqlPersistT a)

type MonadHandlerDB = forall a . (MonadHandler a => m ~ SqlPersistT a)

type MonadHandlerDB m = forall a . (MonadHandler a => m ~ SqlPersistT a)

错误之一:

Couldn't match type `m' with `ReaderT backend0 m0
`m' is a rigid type variable bound by
the type signature for:
  f:: forall (m :: * -> *).
      MonadHandlerDB m =>
      m ()

SqlPersistT 定义为

type SqlPersistT = ReaderT SqlBackend

如何表达这种约束?

我认为这实现了你想要的:

{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeSynonymInstances #-}

import Control.Monad.Trans.Reader (ReaderT (ReaderT))
import Database.Persist.Sql (SqlPersistT)
import Yesod.Core (MonadHandler)

f :: MonadHandlerDB m => m ()
f = undefined

class (MonadHandler (Sub m), m ~ SqlPersistT (Sub m)) => MonadHandlerDB m where
  type Sub m :: * -> *

instance MonadHandler m => MonadHandlerDB (SqlPersistT m) where
  type Sub (SqlPersistT m) = m

但是请注意,我认为这在实践中确实不太好用。它使 m 看起来好像是完全多态的,但实际上,它只能是 SqlPersistT.

中的一些单子。

约束很强大,但我认为像这样的约束很可能会混淆其用户。