将类型约束添加到Haskell中的实例声明的上下文中

时间:2010-11-17 17:09:36

标签: haskell functional-programming instance typeclass

我试图表示加权边。我最终想让OutE成为Eq和Ord的一个实例,其约束条件是etype是Eq和Ord的一个实例。假设我有以下文件作为temp.hs:

data (Ord etype)=> OutE vtype etype = OutE {destVertex:: vtype, edgeValue::etype}

applyFunBy accessor ordfun = (\x y -> (ordfun (accessor x) (accessor y)))

instance Eq (OutE vtype etype) where
    --(==) :: Ord etype => (OutE vtype etype) -> (OutE vtype etype) -> Bool
    --(/=) :: Ord etype => (OutE vtype etype) -> (OutE vtype etype) -> Bool
    (==) = applyFunBy edgeValue (==)
    (/=) = applyFunBy edgeValue (/=)

当我在ghci中加载它时,我收到以下错误:

temp.hs:10:19:
    Could not deduce (Ord etype)
      from the context (Eq (OutE vtype etype))
      arising from a use of `edgeValue' at temp.hs:10:19-27
    Possible fix:
      add (Ord etype) to the context of the instance declaration
    In the first argument of `applyFunBy', namely `edgeValue'
    In the expression: applyFunBy edgeValue (==)
    In the definition of `==': == = applyFunBy edgeValue (==)

temp.hs:11:19:
    Could not deduce (Ord etype)
      from the context (Eq (OutE vtype etype))
      arising from a use of `edgeValue' at temp.hs:11:19-27
    Possible fix:
      add (Ord etype) to the context of the instance declaration
    In the first argument of `applyFunBy', namely `edgeValue'
    In the expression: applyFunBy edgeValue (/=)
    In the definition of `/=': /= = applyFunBy edgeValue (/=)
Failed, modules loaded: none.

如果包含(==)和(\ =)类型签名的行,我会得到:

temp.hs:6:1:
    Misplaced type signature:
    == ::
      (Ord etype) => (OutE vtype etype) -> (OutE vtype etype) -> Bool

temp.hs:7:1:
    Misplaced type signature:
    /= ::
      (Ord etype) => (OutE vtype etype) -> (OutE vtype etype) -> Bool

2 个答案:

答案 0 :(得分:6)

您在etype的定义中将Ord限制为OutE

data (Ord etype) => OutE vtype etype = ...

但是在Eq实例中,您实际上是在尝试无限制地为任何 etype定义实例。

instance Eq (OutE vtype etype) where

当然这不起作用,因为OutE本身只是为Ord etype定义的,因此您还必须将类型类约束添加到实例定义中。

instance (Ord etype) => Eq (OutE vtype etype) where

请注意,==/=的一个定义足以使类型类工作。


请注意,它通常更容易,因此被认为是更好的样式,不在data - 类型上有类型类约束,而只是在实际需要类型类功能的实例/方法上。

在许多情况下,一个人不需要约束,最终会得到不必要的笨拙类型签名。

拿走,例如一些有序的地图类型Ord key => Map key value

如果我们只想列出所有密钥怎么办?或者获得元素的数量?我们不需要Ord这些键,所以为什么不让地图不受限制地使用简单的

getKeys :: Map key value -> [key]
getLength :: Map key value -> Int

只需在像

这样的函数中真正需要它时添加类型类
insert :: Ord key => key -> value -> Map key value

答案 1 :(得分:2)

data (Ord etype)=> OutE vtype etype = OutE {destVertex:: vtype, edgeValue::etype}

第一个问题:这是糟糕的风格。您的数据类型声明不应该有约束。将约束留给函数,就像容器包一样。

instance Eq (OutE vtype etype) where

第二个“问题”。您可以在数据声明后添加deriving (Eq)。我猜你知道这一点,并且正在为你自己的学习明确写出这个实例(对你有好处)......

instance Eq (OutE vtype etype) where
    (==) = applyFunBy edgeValue (==)
    (/=) = applyFunBy edgeValue (/=)

第三个问题:如果属于Eq类,则无法比较权益值。所以你想说etype受到Eq:

的约束
instance (Eq etype) => Eq (OutE vtype etype) where
    (==) = applyFunBy edgeValue (==)
    (/=) = applyFunBy edgeValue (/=)

第四,您实际上不需要为(==)和(/ =)编写实例。一旦您定义了其中一个,默认值就会起作用。