是否有必要在类声明的类上下文中指定每个超类?

时间:2011-07-21 20:33:26

标签: haskell

hxt包中的ArrowList类具有以下声明:

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

ArrowPlus类声明为: class ArrowZero a => ArrowPlus a where ...

ArrowZero类声明为: class Arrow a => ArrowZero a where ...

ArrowApply类声明为: class Arrow a => ArrowApply a where ...

为什么不能把它写成: class (ArrowPlus a, ArrowApply a) => ArrowList a where ......?

1 个答案:

答案 0 :(得分:6)

不,没有必要包括所有超类。如果你写

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

它会起作用。但是,以下是明确提及所有超类的两个可能原因。

  1. 它可能更具可读性,因为您可以一目了然地了解所有超类的内容。

  2. 它可能稍微更有效,因为显式列出超类将导致在运行时直接字典查找,而对于传递超类,它将首先查找超类的字典和然后在那里查找类成员。

    例如,请使用此继承链:

    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
    

    查看为此生成的核心(使用ghc -c -ddump-simpl),我们看到这会生成一系列查找调用。它首先在Baz中查找Xyzzy字典,然后在其中查找Bar字典,然后查找Foo,最后查找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)))
    

    修改Xyzzy的定义以明确提及Foo

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

    我们发现现在可以直接从Foo获取Xyzzy词典并在其中查找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)
    

    请注意,这可能是针对GHC的。使用版本7.0.2进行测试。