2

我有一段非常简单的代码如下:

{-# LANGUAGE
    MultiParamTypeClasses,
    FunctionalDependencies,
    FlexibleInstances,
    FlexibleContexts
#-}

class Graph g n e | g -> n e where
    nodes           :: g -> [n]                             
    edge            :: g -> (n,n) -> Maybe e                

instance Graph g Int e where
    nodes g = []
    edge g (n1,n2) = Nothing

我收到与功能依赖项之一的覆盖条件失败相关的错误。我是否需要添加 -XUndecidableInstances 才能允许这样做?或者我该如何解决这个问题?谢谢

4

2 回答 2

5

您的问题不是Intbut e。覆盖条件记录在GHC 的手册Sect 中。7.6.3.2。放宽了实例上下文的规则并说:

覆盖条件。对于类的每个函数依赖项 tvs left -> tvs right,S(tvs right ) 中的每个类型变量都必须出现在 S(tvs left ) 中,其中 S 是将类声明中的每个类型变量映射到对应的替换输入实例声明。

在实践中是什么意思?在您的情况下,您的功能依赖项表示g -> n e,这意味着对于每个实例,由n和表示e的类型对于由 表示的类型是唯一的g。现在假设您正在定义一个实例

instance Graph SomeTypeG SomeTypeN SomeTypeE where
    ...

覆盖条件表示任何类型变量出现在SomeTypeESomeTypeN必须出现在SomeTypeG. 如果不满足怎么办?假设一个类型变量a出现在SomeTypeE但没有出现在SomeTypeG. 然后,对于 fixed SomeTypeG,我们将通过用不同的类型替换a.

在你的情况下

instance Graph g Int e where
    ...

e是这样一个类型变量,所以通过覆盖条件它必须出现在 中g,这是不正确的。因为它没有出现在那里,所以您的定义将暗示它Graph g Int Int是一个实例,Graph g Int (Maybe Char)是另一个实例等,这与要求恰好有一个的功能依赖相矛盾。

如果你定义了类似的东西

instance Graph g Int Char where

那么就可以了,因为Intand中没有类型变量Char。另一个有效实例可能是

instance Graph (g2 e) Int e where

现在哪里g2有样了* -> *。在这种情况下,e出现在 中g2 e,它满足覆盖条件,并且确实e总是由 唯一确定g2 e

于 2013-02-01T18:40:20.737 回答
1

您的功能依赖表明您选择的类型 g 分别决定了您的节点和元素类型 n 和 e。那么,说所有图形类型 g(对 g 一无所知)确定节点类型为 Int 是否有意义?

于 2013-02-01T16:35:16.347 回答