Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it necessary to specify every superclass in a class context of a class declaration?

Tags:

haskell

The ArrowList class from the hxt package has the following declaration:

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

The ArrowPlus class is declared as: class ArrowZero a => ArrowPlus a where ...

The ArrowZero class is declared as: class Arrow a => ArrowZero a where ...

And the ArrowApply class is declared as: class Arrow a => ArrowApply a where ...

Why can't it just be written as: class (ArrowPlus a, ArrowApply a) => ArrowList a where ...?

like image 347
qubital Avatar asked Jul 21 '11 20:07

qubital


Video Answer


1 Answers

No, it's not necessary to include all the superclasses. If you write

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

it will work. However, here are two possible reasons for mentioning all the superclasses explicitly.

  1. It might be more readable as you can tell at a glance what all the superclasses are.

  2. It might be slightly more efficient, as listing the superclasses explicitly will result in a direct dictionary lookup at runtime, while for a transitive superclass it will first lookup the dictionary for the superclass and then lookup the class member in that.

    For example, take this inheritance chain:

    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
    

    Looking at the generated core for this (with ghc -c -ddump-simpl), we see that this generates a chain of lookup calls. It first looks up the dictionary for Baz in Xyzzy, then Bar in that, then Foo, and finally it can look up 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)))
    

    Modifying the definition of Xyzzy to explicitly mention Foo:

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

    We see that it can now get the Foo dictionary straight from the Xyzzy one and look up foo in that.

    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)
    

    Note that this may be GHC-specific. Tested with version 7.0.2.

like image 50
hammar Avatar answered Oct 21 '22 08:10

hammar