Tengo un tipo Id ay estoy tratando de evitar la coerción accidental, por ejemplo, un Id Doublea un Id Int.
Si entiendo los tipos de letra correctamente, no se debe compilar lo siguiente.
{-# LANGUAGE RoleAnnotations #-}
import Data.Coerce (coerce)
type role Id nominal
newtype Id a = Id String
badKey :: Id Int
badKey = coerce (Id "I point to a Double" :: Id Double)
Lamentablemente, sí:
Prelude> :load Id.hs
[1 of 1] Compiling Main ( Id.hs, interpreted )
Ok, one module loaded.
*Main> :type badKey
badKey :: Id Int
¿Qué me estoy perdiendo sobre los roles de tipo?

ainIdes una variable fantasma y no tiene impacto en el valor real en su interior. Si lo hubiera hechonewtype Id a = Id a, entonces la coerción habría fallado.type roleera hacer que ese no fuera el caso. Esta pregunta es por qué eso no funcionó.Respuestas:
Coercibletiene tres posibles "tipos" de instancias (que son generadas automáticamente por el compilador, no definidas por el usuario). Solo uno de ellos está afectado por los roles .representationalophantom. Por ejemplo, puede coaccionar unMap Char IntaMap Char (Data.Monoid.Sum Int)porque porqueMaptenemostype role Map nominal representational.En su ejemplo, se aplica la tercera regla. Si el nuevo tipo se hubiera definido en otro módulo y el constructor no se hubiera importado, la coerción habría fallado (para que funcione nuevamente, necesitaría cambiar el rol a
phantom).El comportamiento especial algo sorprendente para los nuevos tipos se explica en este número de GHC.
fuente