Estoy tratando de crear mi propio tipo de datos, que formará parte de la clase Monad, pero
newtype Container a = Container a deriving Monad
me da este error:
* Can't make a derived instance of `Monad Container'
(even with cunning GeneralizedNewtypeDeriving):
cannot eta-reduce the representation type enough
* In the newtype declaration for `Container'
|
30 | newtype Container a = Container a deriving Monad
Funciona bien para otras clases (Mostrar, por ejemplo), pero no para Monad, entonces, ¿cómo puedo convencer a ghci de que instale mi clase Container to Monad?
Gracias
a
no es una instancia de mónada, por lo tanto, no tiene mucho sentido. Si, por ejemplo, lo usanewtype Container a = Container [a] deriving (Functor, Applicative, Monad)
, funcionará, ya que[]
es una instancia deMonad
.GenerlizedNewtypeDeriving
es específicamente para "levantar" las instancias del tipo envuelto al nuevo tipo. La pregunta de cómo (o si) uno puede derivar automáticamente unaMonad
instancia paraContainer
todavía es interesante. (El hecho quebase
define laMonad
instancia paraIdentity
explícito sugiere que no puede)Monad
no es una de las clases de tipos que el estándar Haskell pone a disposición para ser derivadas automáticamente (Show
es, junto con algunas otras básicas). Sin embargo, creo que GHC puede hacerlo con las extensiones correctas.GeneralizedNewtypeDeriving
está habilitado, y una pregunta es por qué todavía no funciona.Respuestas:
Solo un conjunto fijo de clases estándar admite la derivación de fábrica:
En particular
Monad
no pertenece a esa lista, ni a la extendida.Hay más extensiones que generalizan derivando a clases arbitrarias, pero no pueden ser 100% automatizadas. Alguien en algún lugar tiene que especificar cómo se debe hacer esa derivación; Dependiendo de la clase, se puede requerir que el usuario cargue con la carga porque hay información que fundamentalmente no se puede inferir.
En su caso, el nuevo tipo
Container
es representacionalmente equivalente a laIdentity
mónada en la biblioteca estándar, por lo que puede usarDerivingVia
:Solo hay una instancia sensata en esta situación muy particular, pero la mayoría de las veces no es fácil saber cuál debería ser la instancia, incluso si solo hay una.
fuente
Functor
yApplicative
, pero luego comparar el tipo deContainer 3 >>= (+1)
conIdentity 3 >>= (+1)
. No sé si eso está relacionadoDerivingVia
o no.Container 3 >>= (+ 1) :: Num (Container b) => Container b
yIdentity 3 >>= (+ 1) :: Num b => Identity b
. No estoy seguro de por quéContainer b
, en lugar deb
, tiene laNum
restricción.)(+ 1) :: Num c => c -> c
como flecha de Kleisli(+ 1) :: a -> Container b
necesitas unificarc ~ Container b
. Pero no estoy seguro de cuál es su punto de partida.Identity
que no se defineContainer
, segúnIdentity 3 >>= (+1)
evalúaIdentity 4
.instance Num a => Num (Identity a)
definido.