向Haskell中实例声明的上下文添加类型约束
我试图表示加权边。我最终希望OutE成为Eq和Ord的一个实例,但约束条件是etype是Eq和Ord的一个实例。假设我有以下文件作为temp.hs:向Haskell中实例声明的上下文添加类型约束,haskell,functional-programming,instance,typeclass,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
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.
如果包括(==)和(\=)的类型签名行,我得到:
第一个问题:这是一种糟糕的风格。数据类型声明不应该有约束。将约束留给函数,就像containers包那样
instance Eq (OutE vtype etype) where
第二个“问题”。您可以在数据声明之后添加派生(Eq)
。我猜您知道这一点,并且正在为自己的学习明确地编写实例(对您有好处)
第三个问题:如果权益属于Eq
类别,则无法对其进行比较。所以你想说etype
受等式约束:
instance (Eq etype) => Eq (OutE vtype etype) where
(==) = applyFunBy edgeValue (==)
(/=) = applyFunBy edgeValue (/=)
第四,实际上不需要为(==)和(/=)都编写实例。一旦您定义了其中一个,默认值将起作用。您在定义
OutE
时将etype
限制为Ord
:
data (Ord etype) => OutE vtype etype = ...
但是在Eq
实例中,实际上您正试图不受限制地为任何etype
定义实例
instance Eq (OutE vtype etype) where
当然,这不起作用,因为OutE
本身只是为Ord-etype
s定义的,因此您还必须将typeclass约束添加到实例定义中
instance (Ord etype) => Eq (OutE vtype etype) where
请注意,=
或/=
的一个定义足以让typeclass工作
注意,在
数据
-类型上不设置typeclass约束,而仅在实际需要typeclass功能的实例/方法上设置,这通常更容易,因此被认为是更好的样式
在许多情况下,不需要约束,只会得到不必要的笨拙类型签名
例如,一些有序映射类型Ord key=>map key value
如果我们只想列出所有的键呢?或者获取元素的数量?对于这些,我们不需要将键设置为Ord
,因此,为什么不使用simple让map不受限制呢
getKeys :: Map key value -> [key]
getLength :: Map key value -> Int
当我们在函数中真正需要它时,只需添加typeclass,如
insert :: Ord key => key -> value -> Map key value
派生(Eq)
将基于所有记录字段生成相等运算符(从而生成一个带有Eq vtype
的笨重的Eq
实例),而问题中给出的显式实例只是基于edgeValue
进行比较。是的,直到写下该位之后,我才注意到他正在这样做。谢谢你指出这一点。
instance (Ord etype) => Eq (OutE vtype etype) where
getKeys :: Map key value -> [key]
getLength :: Map key value -> Int
insert :: Ord key => key -> value -> Map key value