Haskell “哈斯克尔”;模式“中的分析错误”;从Eq导出实例时
我在“向你学习一个非常好的Haskell!”的帮助下学习Haskell,目前正在尝试理解类型类和实例。 LYAH提供了一个名为Haskell “哈斯克尔”;模式“中的分析错误”;从Eq导出实例时,haskell,parse-error,Haskell,Parse Error,我在“向你学习一个非常好的Haskell!”的帮助下学习Haskell,目前正在尝试理解类型类和实例。 LYAH提供了一个名为TrafficLight的类型定义如下: data TrafficLight = Red | Yellow | Green 现在,TrafficLight应该是显示以下行为的Eq的一个实例: instance Eq TrafficLight where Red == Red = True Green == Green = True Yellow
TrafficLight
的类型定义如下:
data TrafficLight = Red | Yellow | Green
现在,TrafficLight
应该是显示以下行为的Eq
的一个实例:
instance Eq TrafficLight where
Red == Red = True
Green == Green = True
Yellow == Yellow = True
_ == _ = False
为了理解这是如何工作的,我编写了自己的文件,名为Shop.hs
,试图覆盖ItemSlot
的Eq
行为
module Shop where
type Number = Int
data Item =
BellPepper
| Cabbage
| Carrot
| Lettuce
| Onion
| Potato
| Tomato
deriving (Show, Read, Eq)
data ItemSlot = ItemSlot {
item :: Item,
number :: Number
} deriving (Show)
instance Eq ItemSlot where
((item a) == (item a)) = True -- line that contains the error
_ == _ = False
但是,如果在GHCi中加载该文件,则会出现以下错误:
Prelude> :l Shop.hs
[1 of 1] Compiling Shop ( Shop.hs, interpreted )
Shop.hs:21:11: Parse error in pattern: item
Failed, modules loaded: none.
(我必须承认,我对这里的正确语法感到相当困惑——是项目a
还是仅仅项目
?
仅使用项
失败,并出现相同的错误,并且使用更多的括号——就像在SO上的另一个类似问题中的答案一样——似乎也没有帮助。)
我的猜测是,我无法使用
ItemSlot
中使用的记录语法提供的item
函数,但我不知道如何解决这个问题。模式通常以构造函数开始。ItemSlot
类型的构造函数是ItemSlot
,因此您可以使用它:
instance Eq ItemSlot where
ItemSlot item a == ItemSlot item' a' = -- use item, item', a, and a'
或者,因为您已经将ItemSlot
定义为记录,所以有所谓的模式记录语法。您可以按名称而不是位置绑定变量:
instance Eq ItemSlot where
ItemSlot { item = foo, number = a } == ItemSlot { item = foo', number = a' }
= -- use foo, foo', a, and a'
如果您不介意混淆的话,您当然可以隐藏姓名:
instance Eq ItemSlot where
ItemSlot { item = item, number = a } == ItemSlot { item = item', number = a' }
= -- use item, item', a, and a'
为了方便起见,Haskell中的模式可以嵌套;因此,如果您想匹配ItemSlot
s,例如,两者都有BellPepper
s,您可以编写
instance Eq ItemSlot where
ItemSlot BellPepper a == ItemSlot BellPepper a' = True
-- or, equivalently
ItemSlot { item = BellPepper } == ItemSlot { item = BellPepper } = True
虽然通常您会将
项目
的比较委托给项目
的Eq
实例。模式匹配在交通灯
示例中起作用,因为您
只需要知道构造函数是什么(红色
、绿色
或黄色
)
要知道它们是否相等,但您的ItemSlot
s仅为
如果项
字段中的数据相等,则相等,因此需要进行检查
右边有一个等式:
instance Eq ItemSlot where
ItemSlot {item=i} == ItemSlot {item=j} = i == j
这相当于
instance Eq ItemSlot where
ItemSlot i _ == ItemSlot j _ = i == j
但更能证明未来,因为如果您添加另一个字段
如果不想更改==
的含义,可以保留第一个版本
单独地(您可能会争辩说,当您添加字段时,应该重新访问==
,
但是使用{item=
语法可以在我的
经验
最干净的是
instance Eq ItemSlot where
i == j = item i == item j
正如安泰S-Z提醒我的那样(谢谢)
如果你用
eg1 = ItemSlot {item = Carrot, number = 3}
eg2 = ItemSlot {item = Onion, number = 3}
eg3 = ItemSlot {item = Onion, number = 42}
eg4 = ItemSlot {item = Carrot, number = undefined}
eg5 = ItemSlot {item = Carrot}
你会发现eg5
给了你一个警告。你被允许
使用记录时忽略字段,因此上面的Eq
的第一个版本是
好的,但是如果您要定义一个记录,Haskell希望您提供所有
数据
您可以检查eg4==eg1
和eg2==eg4
甚至eg2==eg5
,而无需
问题-延迟计算意味着它在检查==
时不检查数字字段,
但是,如果您只键入
eg4
或eg5
,它将不会完成,因为它遇到了未定义的值。谢谢您的帮助,您的第一个示例为我完成了这项操作(我只想比较相同的项目,而不是相同的数字)。我想我自己永远也不会想到这一点。再加上一点:您可以使用项
访问器功能(或任何其他功能)在定义的右侧。因此,实例Eq ItemSlot,其中is1==is2=item is1==item is2
也会起作用。不过,模式匹配方式可能更好。@Antal S-Z:这正是我最初认为最好的方式,但显然我在写答案时分心了。我已经编辑了答案,但没有更新ted你的评论。谢谢提醒我。