haskell generics deriving

haskell - ¿Cuál es la diferencia entre `DeriveAnyClass` y una instancia vacía?



generics deriving (1)

Los documentos de GHC dicen:

El contexto de la instancia se generará de acuerdo con las mismas reglas utilizadas al derivar la Eq (si el tipo del tipo es * ), o las reglas para el Functor (si el tipo del tipo es (* -> *) ). Por ejemplo

instance C a => C (a,b) where ... data T a b = MkT a (a,b) deriving( C )

La cláusula deriving generará

instance C a => C (T a b) where {}

Las restricciones C a y C (a,b) se generan a partir de los argumentos del constructor de datos, pero este último se simplifica a C a .

Entonces, de acuerdo con las reglas Eq , su cláusula deriving genera ...

instance ToNamedRecord Int => ToNamedRecord Foo where

... que no es lo mismo que ...

instance ToNamedRecord Foo where

... en que el primero solo es válido si hay una instance ToNamedRecord Int en el alcance (que aparece en su caso).

Pero me parece que la especificación es algo ambigua. ¿Debería el ejemplo realmente generar ese código, o debería generar una instance (C a, C (a, b)) => instance C (T ab) y permitir que el solucionador descargue la segunda restricción? En su ejemplo, parece que está generando tales restricciones incluso para campos con tipos totalmente concretos.

Dudo en llamar a esto un error, porque es cómo funciona la Eq , pero dado que la intención de DeriveAnyClass es hacer que sea más rápido escribir instancias vacías , parece poco intuitivo.

Usando el paquete de cassava , se compila lo siguiente:

{-# LANGUAGE DeriveGeneric #-} import Data.Csv import GHC.Generics data Foo = Foo { foo :: Int } deriving (Generic) instance ToNamedRecord Foo

Sin embargo, lo siguiente no:

{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveAnyClass #-} import Data.Csv import GHC.Generics data Foo = Foo { foo :: Int } deriving (Generic, ToNamedRecord)

El compilador reporta:

test.hs:7:50: No instance for (ToNamedRecord Int) arising from the first field of ‘Foo’ (type ‘Int’) Possible fix: use a standalone ''deriving instance'' declaration, so you can specify the instance context yourself When deriving the instance for (ToNamedRecord Foo)

Esto me deja con dos preguntas: ¿Por qué la segunda versión no es idéntica a la primera? ¿Y por qué el compilador espera encontrar una instancia para ToNamedRecord Int ?