在 Haskell 中为自定义数据类型创建 Eq 实例
Creating Instance of Eq for custom data type in Haskell
我已经为 Haskell 中的数字表示创建了一些自定义数据类型,现在我想为它实现 Eq 实例,但我不知何故卡住了。所以我已经做了:
data Digit = Zero | One | Two
type Digits = [Digit]
data Sign = Pos | Neg -- Pos fuer Positive, Neg fuer Negative
newtype Numeral = Num (Sign,Digits)
instance Eq Sign where
(==) Pos Pos = True
(==) Neg Neg = True
(==) _ _ = False
instance Eq Digit where
(==) Zero Zero = True
(==) One One = True
(==) Two Two = True
(==) _ _ = False
现在我想检查自定义类型数字中的登录,所以我尝试了这个:
instance (Eq Sign) => Eq (Numeral) where
(==) Num(x,_)== Num(y,_) = x==y
但我收到此错误:模式解析错误:(==)
主要是将我已经写在评论中的内容以更充实的形式呈现:
您的代码存在一些问题:
- 您必须缩进
instance
声明下的代码。这样你就可以告诉编译器哪些代码属于实例声明。
在下一行中,您要求对具体类型 (Eq Sign =>
) 进行类型 class 约束。这在标准 Haskell 中是不可能的,即使您遵循编译器说明并启用 FlexibleInstances
语言扩展也没有意义。
instance (Eq Sign) => Eq (Numeral) where
类型 class 约束仅用于类型变量。例如:
double :: Num a => a -> a
double x = x + x
这里我们说,函数 double
仅适用于实现 Num
的所有类型。 double :: Num Int => Int -> Int
另一方面是多余的,因为我们已经知道 Int
有一个 Num
实例。 Eq Sign
.
也一样
对于实例,只有当您为其编写实例的类型包含另一个多态类型时,此类约束才有意义。福克斯例子instance Ord a => Ord [a]
。这里我们将使用列表元素的 Ord
实例来按字典顺序排列列表。
您可以用中缀或前缀形式定义 (==)
,但不能同时使用这两种形式。所以 (==) (Num (x,_)) (Num (y,_)) = x == y
或 Num (x,_) == Num (y,_) = x == y
.
用新类型的元组来创建产品类型是相当奇怪的。如果您想使用更复杂的基础类型已经存在的功能,通常会使用新类型。但是这里不是这种情况,您只需要 Digits
和 Sign
.
的正常乘积
您只是在比较 Sign
个数字。虽然从技术上讲是一个有效的 Eq
实例,但我认为您还想比较可能截断前导零的数字的数字。在下面的代码中,为了简单起见,我没有截断零。
data Digit = Zero | One | Two
type Digits = [Digit]
data Sign = Pos | Neg
data Numeral = Num Sign Digits
instance Eq Sign where
(==) Pos Pos = True
(==) Neg Neg = True
(==) _ _ = False
instance Eq Digit where
(==) Zero Zero = True
(==) One One = True
(==) Two Two = True
(==) _ _ = False
instance Eq Numeral where
Num s1 x1 == Num s2 x2 = s1 == s2 && x1 == x2
我已经为 Haskell 中的数字表示创建了一些自定义数据类型,现在我想为它实现 Eq 实例,但我不知何故卡住了。所以我已经做了:
data Digit = Zero | One | Two
type Digits = [Digit]
data Sign = Pos | Neg -- Pos fuer Positive, Neg fuer Negative
newtype Numeral = Num (Sign,Digits)
instance Eq Sign where
(==) Pos Pos = True
(==) Neg Neg = True
(==) _ _ = False
instance Eq Digit where
(==) Zero Zero = True
(==) One One = True
(==) Two Two = True
(==) _ _ = False
现在我想检查自定义类型数字中的登录,所以我尝试了这个:
instance (Eq Sign) => Eq (Numeral) where
(==) Num(x,_)== Num(y,_) = x==y
但我收到此错误:模式解析错误:(==)
主要是将我已经写在评论中的内容以更充实的形式呈现:
您的代码存在一些问题:
- 您必须缩进
instance
声明下的代码。这样你就可以告诉编译器哪些代码属于实例声明。 在下一行中,您要求对具体类型 (
Eq Sign =>
) 进行类型 class 约束。这在标准 Haskell 中是不可能的,即使您遵循编译器说明并启用FlexibleInstances
语言扩展也没有意义。instance (Eq Sign) => Eq (Numeral) where
类型 class 约束仅用于类型变量。例如:
double :: Num a => a -> a double x = x + x
这里我们说,函数
也一样double
仅适用于实现Num
的所有类型。double :: Num Int => Int -> Int
另一方面是多余的,因为我们已经知道Int
有一个Num
实例。Eq Sign
.对于实例,只有当您为其编写实例的类型包含另一个多态类型时,此类约束才有意义。福克斯例子
instance Ord a => Ord [a]
。这里我们将使用列表元素的Ord
实例来按字典顺序排列列表。您可以用中缀或前缀形式定义
(==)
,但不能同时使用这两种形式。所以(==) (Num (x,_)) (Num (y,_)) = x == y
或Num (x,_) == Num (y,_) = x == y
.用新类型的元组来创建产品类型是相当奇怪的。如果您想使用更复杂的基础类型已经存在的功能,通常会使用新类型。但是这里不是这种情况,您只需要
Digits
和Sign
. 的正常乘积
您只是在比较
Sign
个数字。虽然从技术上讲是一个有效的Eq
实例,但我认为您还想比较可能截断前导零的数字的数字。在下面的代码中,为了简单起见,我没有截断零。
data Digit = Zero | One | Two
type Digits = [Digit]
data Sign = Pos | Neg
data Numeral = Num Sign Digits
instance Eq Sign where
(==) Pos Pos = True
(==) Neg Neg = True
(==) _ _ = False
instance Eq Digit where
(==) Zero Zero = True
(==) One One = True
(==) Two Two = True
(==) _ _ = False
instance Eq Numeral where
Num s1 x1 == Num s2 x2 = s1 == s2 && x1 == x2