以下是我对这些答案的理解。我花了一些时间才理解,因此我把它写下来,或许能帮到其他人。
传统的类型类声明(Haskell 98)class (Eq a) => MyClass a where
表示如果a
是MyClass
的实例,那么a
必须是Eq
的实例。左侧的Eq a
(表示a
是Eq
的实例)是一个谓词,如果右侧MyClass a
(表示a
是MyClass
的实例)为真,则该谓词也必须为真。
因此,换句话说,类声明就像class ($Predicate) => MyClass classInstance
,其中$Predicate
可以是例如Eq a
,这意味着a
是Eq
的实例。
但是,如果启用了FlexibleContexts
语言扩展,则谓词可以比ATypeClass typeParameter
更复杂。
它可以是ATypeClass SomeComplexType
,这意味着 - 通过将Haskell 98的规则泛化,SomeComplexType
是ATypeClass
的一个实例。
这个泛化过程在Haskell报告中隐含地描述(如Daniel的答案所解释的那样)。
以下三个简短的程序演示了这个泛化规则。第一个编译第二个不编译,第三个再次编译。
第二个无法编译,因为Smells
不是IntLike
类声明中所需的StringLike
。然而,如果我们删除该约束条件(在第三个程序中),则程序再次编译。
这里有一个玩具示例,可以编译:
{-# LANGUAGE FlexibleContexts #-}
class StringLike a where
getString :: a->String
class (StringLike Smells) =>IntLike a where
getInt :: a-> Int
instance IntLike Colors where
getInt x = 0
instance StringLike Colors where
getString x = "Hello"
instance StringLike Smells where
getString x = "Bad"
data Colors = Blue | Red
data Smells = Rose | Trash
以下操作失败了:
{-# LANGUAGE FlexibleContexts #-}
class StringLike a where
getString :: a->String
class (StringLike Smells) =>IntLike a where
getInt :: a-> Int
instance IntLike Colors where
getInt x = 0
instance StringLike Colors where
getString x = "Hello"
data Colors = Blue | Red
data Smells = Rose | Trash
附带错误信息:
test.hs:10:10:
No instance for (StringLike Smells)
arising from the superclasses of an instance declaration
In the instance declaration for `IntLike Colors'
Failed, modules loaded: none.
然而,以下的代码可以正常编译:
{-# LANGUAGE FlexibleContexts #-}
class StringLike a where
getString :: a->String
class (StringLike Smells) =>IntLike a where
getInt :: a-> Int
instance StringLike Colors where
getString x = "Hello"
data Colors = Blue | Red
data Smells = Rose | Trash
class Functor (F a) => Funky a
只是意味着对于声明为Funky
类的所有实例,必须存在一个F a
的Functor
实例(对于相同的a
)。这与class Eq a => Ord a
的含义没有任何区别,后者意味着对于所有Ord
的实例,必须存在一个Eq
的实例。 - Benclass Eq a => Eq (Maybe a)
这样的代码。无论是不是 Haskell 98,用class Eq (Maybe a) => Eq a
来表达并没有涉及到任何新概念。 - Ben