2012-06-22 10 views
18

GHC tiene algunos indicadores de idioma, como DeriveFunctor, DeriveDataTypeable etc., que permiten la generación de compiladores de instancias derivadas para clases de tipos distintas a las permitidas en Haskell 98. Esto tiene sentido especialmente para algo como Functor, donde las leyes de esa clase dictar una instancia obvia, derivada "natural".¿Por qué GHC no puede derivar instancias para Monoid?

¿Por qué no para Monoid? Parece que para cualquier tipo de datos con un solo constructor de datos:

data T = MkT a b c ... 

se podría producir mecánicamente una instancia Monoid (con perdón del pseudocódigo):

instance (Monoid a, Monoid b, Monoid c, ...) => Monoid T where 
    mempty = 
    MkT mempty mempty mempty ... 
    mappend (MkT a1 b1 c1 ...) (MkT a2 b2 c2 ...) = 
    MkT (mappend a1 a2) (mappend b1 b2) (mappend c1 c2) ... 

Soy consciente de que el paquete de deriveprovides this, pero mi pregunta específica es si hay una razón por la cual GHC no lo hace.

+0

@sdcvvc: Parece una respuesta válida a la pregunta. Tal vez deberías publicarlo como tal? –

+0

OK, hice una respuesta. – sdcvvc

+1

Por lo general, solo hay una manera sensata de hacer una instancia de 'Functor'. Lo mismo no es cierto sobre 'Monoid'. – augustss

Respuesta

14

Es realmente una decisión arbitraria no poder derivar Monoid, pero los monoides también son muy generales, por lo que normalmente hay muchas maneras de hacer que un tipo sea monoide. Aquí está un ejemplo:

data T = A | B | C deriving (Eq, Ord, Enum) 

type Mon a = (a, a -> a -> a) 

m1, m2, m3, m4 :: Mon T 
m1 = (A, max) 
m2 = (C, min) 
m3 = (A, \ x y -> toEnum $ (fromEnum x + fromEnum y) `rem` 3) 
m4 = (B, f4) 
f4 A _ = A 
f4 B x = x 
f4 C _ = C 

Esta muestra cuatro formas razonables para que T un monoide (con Mon que contiene la unidad y la operación binaria). El primero es el monoide tomando el máximo, el segundo el monoide de tomar el mínimo, el tercero el monoide de la aritmética del módulo 3, y el cuarto es el monoide utilizado para el tipo Ordering. Nada realmente se destaca como la forma natural.

7

Puede solicitar lo mismo para Num y algunas otras clases. Sería inconsecuente: todas las demás derivaciones estándar funcionan para tipos de datos con múltiples constructores.

Como reemplazo, puede usar newtype derivando newtype T = MkT (a,b,c) deriving Monoid.

Extensión similar: puede hacer que el tipo de datos vacío sea una instancia de casi todas las clases de tipos.

La cláusula deriving siempre fue ad-hoc e inconveniente para Haskell, ya que solo funcionaba para las clases predefinidas. Agregar aún más extensiones ad-hoc complicaría el lenguaje. En cambio, GHC recientemente recibió soporte para generic deriving.

+1

Bueno, a pesar de que ad-hoc como 'deriva 'puede ser, han seguido expandiendo su poder. Una vez más, sé que hay mecanismos alternativos para derivar 'Monoid'; en su lugar, estoy preguntando específicamente por qué 'DeriveFunctor' (y otros) existe, mientras que' DeriveMonoid' (y otros) no. ¿Es solo arbitrario? – mergeconflict

+2

Al final es arbitrario, pero la extensión propuesta parece ser mucho menos útil. Una característica especial del lenguaje para servir a la mayoría de los funtores me parece buena. Una característica especial del lenguaje para servir a los monoides del producto parece poco para garantizar la adición. Debería pensar en el alcance (si es 'Monoid', ¿qué otras clases?). Tenga en cuenta que los monoides útiles a menudo usan envoltorios de tipo nuevo de todos modos. Entonces usted escribe 'datos T = T (Suma Suma) (Endo Char)' para usar esa forma de derivación, que es un poco feo de usar (necesita coincidir en constructores anidados). – sdcvvc

+2

Hay muchos monoides útiles que son tipos de suma, pero esta implementación no puede derivar ninguna de sus instancias.= ( –

Cuestiones relacionadas