Home > OS >  Cannot represent equality constraint as a custom constraint
Cannot represent equality constraint as a custom constraint

Time:12-11

I have a function type declaration

f :: MonadHandler m => SqlPersistT m ()

Which I want to convert to

f :: MonadHandlerDB m => m ()

I try everything I can think of to define constraint MonadHandlerDB, but cannot get either it or function type declaration to compile, e.g.:

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)

One of the errors:

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 is defined as

type SqlPersistT = ReaderT SqlBackend

How do I express this constraint?

CodePudding user response:

I think this achieves what you want:

{-# 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

But note that I think this is really not very good to use in practice. It makes it seem as if the m is completely polymorphic, but, in fact, it can only ever be some monad inside SqlPersistT.

Constraints are powerful, but I think a constraint like this has a high potential to confuse its users.

  • Related