GeneralizedNewtypeDeriving fails for PersistFieldS

2019-04-30 05:17发布

问题:

I'm trying to define a Markdown newtype, and using GeneralizedNewtypeDeriving to automatically define new instances:

import Text.Markdown
import Yesod.Text.Markdown
import Database.Persist.Sql

newtype MarkdownNewT = MarkdownNewT { getMarkdown :: Markdown }
  deriving (Eq, IsString, Monoid, PersistField, PersistFieldSql)

This fails for the PersistFieldSql with the following message:

Could not coerce from ‘m Markdown’ to ‘m MarkdownNewT’
  because ‘m Markdown’ and ‘m MarkdownNewT’ are different types.
  arising from the coercion of the method ‘sqlType’ from type
               ‘forall (m :: * -> *). Monad m => m Markdown -> SqlType’ to type
               ‘forall (m :: * -> *). Monad m => m MarkdownNewT -> SqlType’

Is this due to the new roles features of GHC 7.8.2? In that particular case I don't know what to do, since Markdown is itself a newtype over Text...

Or is this related with the forall on sqlType? What is the reason for this error when all other instances are successfully automatically derived?

Thanks

回答1:

This looks very similar to some of the examples (in particular the Vector one) in the GHC wiki Roles2 page of things that don't work with the current role system, alas.

Basically the problem is that in

class PersistField a => PersistFieldSql a where
    sqlType :: Monad m => m a -> SqlType

the monad m might be instantiated with a type constructor whose argument has nominal role, so that m Markdown and m MarkdownNewT aren't identically represented even if Markdown and MarkdownNewT themselves are - and the current role system has no way of restricting m to disallow such type constructors.