2011-07-21 21 views
7

La clase ArrowList del paquete hxt tiene la siguiente declaración:¿Es necesario especificar cada superclase en un contexto de clase de una declaración de clase?

class (Arrow a, ArrowPlus a, ArrowZero a, ArrowApply a) => ArrowList a where ...

La clase ArrowPlus se declara como: class ArrowZero a => ArrowPlus a where ...

La clase ArrowZero se declara como: class Arrow a => ArrowZero a where ...

Y la clase ArrowApply se declara como: class Arrow a => ArrowApply a where ...

por qué no puede simplemente ser escrito como: class (ArrowPlus a, ArrowApply a) => ArrowList a where ...?

+0

Esto es interesante ... Pensé que podría. – luqui

+0

¿Por qué no probarlo? – fuz

Respuesta

6

No, no es necesario incluir todas las superclases. Si escribe

class (ArrowPlus a, ArrowApply a) => ArrowList a where 

funcionará. Sin embargo, aquí hay dos posibles razones para mencionar explícitamente todas las superclases.

  1. Puede ser más legible, ya que puede decir de un vistazo qué son todas las superclases.

  2. Podría ser ligeramente más eficiente, ya que la lista de las superclases explícitamente dará lugar a una búsqueda de diccionario directa en tiempo de ejecución, mientras que para una superclase transitivos se sucederán las operaciones de búsqueda del diccionario para la superclase y luego buscar el miembro de la clase de ese.

    Por ejemplo, tomar esta cadena de herencia:

    module Example where 
    
    class Foo a where 
        foo :: a -> String 
    
    class Foo a => Bar a 
    class Bar a => Baz a 
    class Baz a => Xyzzy a 
    
    quux :: Xyzzy a => a -> String 
    quux = foo 
    

    Mirando el núcleo generado para este (con ghc -c -ddump-simpl), vemos que esto genera una cadena de llamadas de búsqueda. Primero busca el diccionario para Baz en Xyzzy, luego Bar en eso, luego Foo, y finalmente puede buscar foo.

    Example.quux 
        :: forall a_abI. Example.Xyzzy a_abI => a_abI -> GHC.Base.String 
    [GblId, Arity=1, Caf=NoCafRefs] 
    Example.quux = 
        \ (@ a_acE) ($dXyzzy_acF :: Example.Xyzzy a_acE) -> 
        Example.foo 
         @ a_acE 
         (Example.$p1Bar 
         @ a_acE 
         (Example.$p1Baz @ a_acE (Example.$p1Xyzzy @ a_acE $dXyzzy_acF))) 
    

    La modificación de la definición de Xyzzy mencionar explícitamente Foo:

    class (Foo a, Baz a) => Xyzzy a 
    

    Vemos que ahora puede obtener el diccionario Foo directamente de la Xyzzy uno y mirar hacia arriba en ese foo.

    Example.quux 
        :: forall a_abD. Example.Xyzzy a_abD => a_abD -> GHC.Base.String 
    [GblId, Arity=1, Caf=NoCafRefs] 
    Example.quux = 
        \ (@ a_acz) ($dXyzzy_acA :: Example.Xyzzy a_acz) -> 
        Example.foo @ a_acz (Example.$p1Xyzzy @ a_acz $dXyzzy_acA) 
    

    Tenga en cuenta que esto puede ser específico de GHC. Probado con la versión 7.0.2.

+0

Gracias, eso tiene sentido. – qubital

+3

¿No valdría la pena una optimización del compilador para propagar esas restricciones a las subclases? – fuz

+3

@FUZxxl: Creo que sí, sí.El único inconveniente que puedo ver es que los diccionarios se agrandarán un poco, pero eso no será un problema a menos que tengas un árbol de herencia gigantesco. – hammar

Cuestiones relacionadas