我有这个haskell代码。我已经创建了两种数据类型,然后我想创建一个新的类Mord
,它可以将函数与Mlist
类型进行比较。
import Data.List
data Mlist a = Mlist [a]
data Mordering = MLT deriving (Eq, Show)
s = Mlist [1, 2, 3]
t = Mlist [1, 4, 2, 3]
class Mord a where
mcompare :: a -> a -> Mordering
instance Mord a => Mord (Mlist a) where
mcompare (Mlist xs) (Mlist ys) = MLT
但是如果我尝试mcompare s t
我就会
<interactive>:1:1:
No instance for (Mord Integer)
arising from a use of `mcompare'
Possible fix: add an instance declaration for (Mord Integer)
In the expression: mcompare s t
In an equation for `it': it = mcompare s t
有没有人看到这个问题?
修改:
这是我的新代码:
import Data.List
data Mlist a = Mlist [a]
data Mordering = MEQ | MIN deriving (Eq, Show)
s = Mlist [1, 2, 3]
t = Mlist [1, 4, 2, 3]
class Mord a where
mcompare :: a -> a -> Mordering
instance Mord (Mlist a) where
mcompare (Mlist xs) (Mlist ys)
| length xs == length ys && null (xs \\ ys) = MEQ
| otherwise = MIN
但我现在得到的错误是:
No instance for (Eq a)
arising from a use of `\\'
In the first argument of `null', namely `(xs \\ ys)'
In the second argument of `(&&)', namely `null (xs \\ ys)'
In the expression: length xs == length ys && null (xs \\ ys)
Failed, modules loaded: none.
答案 0 :(得分:4)
Haskell读到了这个:
instance Mord a => Mord (Mlist a) where
mcompare (Mlist xs) (Mlist ys) = MLT
含义“对于我有a
实例的每个Mord
,我也有一个Mord
Mlist a
实例。但是,如果我不这样做Mord
有一个a
个实例,我Mord
也没有Mlist a
个实例。抱歉,让我们有时再出去玩!“
实例声明的Mord a
部分称为上下文;您可以在A Gentle Introduction to Haskell中了解详情。
实例上下文对于类型构造函数很有用,例如代码中的[]
和Mlist
。例如,我们可以查看标准Eq
class和[a]
的{{3}}:
instance (Eq a) => Eq [a] where
[] == [] = True
(x:xs) == (y:ys) = x == y && xs == ys
_xs == _ys = False
这个例子意味着什么?两个空列表是相同的;如果两个非空列表的头部相等且它们的尾部相等,则它们是相等;任何其他两个非空列表都是不相等的;一个空的非空列表是不相等的。
我加粗了上一段的部分内容,因为它有助于回答“为什么实例上下文有用?”好吧,在列表示例中,列表相等的部分定义来自列表的结构,但另一部分基于其元素的相等性。换句话说,除非可以比较其元素的相等性,否则无法比较列表的相等性。
函数是值的经典示例,无法对相等性进行有意义的比较。那么我们如何检查函数列表是否相等?
ghci> (+1) == (*2)
<interactive>:6:6:
No instance for (Eq (a0 -> a0))
arising from a use of `=='
Possible fix: add an instance declaration for (Eq (a0 -> a0))
In the expression: (+ 1) == (* 2)
In an equation for `it': it = (+ 1) == (* 2)
ghci> [(+4)] == [\x -> 2 * x / 3]
<interactive>:8:8:
No instance for (Eq (a0 -> a0))
arising from a use of `=='
Possible fix: add an instance declaration for (Eq (a0 -> a0))
In the expression: [(+ 4)] == [\ x -> 2 * x / 3]
In an equation for `it': it = [(+ 4)] == [\ x -> 2 * x / 3]
因此,要使代码正常工作,您可以删除未使用的实例上下文,或者您需要提供适当的基础实例,即:
instance Mord Int where
mcompare ... = ...
s :: Mlist Int
s = Mlist [1, 2, 3]
t :: Mlist Int
t = Mlist [1, 4, 2, 3]
答案 1 :(得分:3)
instance Mord a => Mord (Mlist a) where
此处您说Mlist a
是Mord
的实例,当且仅当a
是Mord
的实例时。 Integer
不是Mord
的实例,因此Mlist Integer
也不是Mord
的实例。如果您定义实例Mord Integer
,您的代码将起作用。
响应您的编辑:您的新代码不起作用,因为\\
仅适用于可以进行相等性比较的值列表(即作为Eq
类型类实例的类型的值)。由于您的实例没有Eq
约束,因此您说它应该适用于所有类型,但由于\\
不适用于所有类型,因此您不能这样做。向您的实例添加Eq
约束(即instance (Eq a) => Mord (Mlist a) ...
)将解决您的问题。
答案 2 :(得分:0)
我将放大一个特定点,其他答案已经涵盖了当前的问题。
假设您已经设法使用到目前为止所获得的帮助,并且您启动了GHCi并加载了代码。我们试一试:
ghci> mcompare s t
MLT
ghci> mcompare t s
MLT
嗯。这对我来说似乎没什么用处!发生了什么事?
如果我们看一下mcompare
在给出两个Mlist
时实际做了什么 - 确切地说,在此实例声明中:
instance Mord a => Mord (Mlist a) where
mcompare (Mlist xs) (Mlist ys) = MLT
我们可以看到根本没有比较;无论xs
和ys
是什么,mcompare
只返回MLT
。以某种方式合乎逻辑,因为Mordering
数据类型只有一个值:
data Mordering = MLT deriving (Eq, Show)
但是为了表示比较操作的结果,通常需要3个可能的结果:第一个参数小于,等于或大于第二个参数。你可能会说这也是一个“无法比拟”的选择,但是我们不要进入那里!
所以你希望你的Mordering
数据类型包含这三个比较结果,你可以通过添加一些更多的构造函数来实现(这是我在sepp2k的回答的评论中所说的),如: / p>
data Mordering = LessThan
| EqualTo
| GreaterThan
deriving (Eq,Show)
(我猜你的意思可能是data Mordering = MLT | MEQ | MGT deriving (Eq, Show)
?)
这会引发一系列新问题,我会给你一些提示,以帮助你。
首先,我们希望mcompare 3 4
为LessThan
,mcompare 5 5
为EqualTo
,mcompare 7 6
为GreaterThan
,因为3更少比4(等等)。要实现此目的,您需要Mord
Integer
的实例:
instance Mord Integer where
mcompare x y
| x < y = ...
| x == y = ...
| x > y = ...
填补空白不应该太难,我希望!
第二部分有点棘手:假设我们可以比较a
类型的值,我们如何比较Mlist a
类型的值?换句话说,应该如何写出instance Mord a => Mord (Mlist a)
声明? mcompare (Mlist xs) (Mlist ys)
的结果将取决于xs
是否为空,ys
是否为空,如果两者都不为空,则取决于xs
的第一个元素和{ys
1}}比较以及其余元素的比较方式。
我会留下让你弄明白的;不要犹豫,问一个新的问题,显示你有多远,你被困在哪里!