简体   繁体   English

Haskell:“约束中的非类型变量参数:Eq Bit”和“没有使用 '==' 产生 (Eq Bit) 的实例”

[英]Haskell: “Non type-variable argument in the constraint: Eq Bit” and “No instance for (Eq Bit) arising drom a use of '=='”

data Bit = One 
         | Zero
         deriving Show

type Bits = [Bit]

bits2String :: Bits -> String
bits2String [] = ""
bits2String (x:xs) | x == One = "1" ++ bits2String xs
                   | x == Zero = "0" ++ bits2String xs

This Code causes following error message:此代码导致以下错误消息:

No instance for (Eq Bit) arising drom a use of '=='

For this error you can find a lot of solutions on SO.对于这个错误,您可以在 SO 上找到很多解决方案。 They always say you need to add Eq like that:他们总是说你需要像这样添加 Eq:

bits2String :: (Eq Bit) => Bits -> String
bits2String [] = ""
bits2String (x:xs) | x == One = "1" ++ bits2String xs
                   | x == Zero = "0" ++ bits2String xs

But this doesnt work for me and causes following error但这对我不起作用并导致以下错误

Non type-variable argument in the constraint: Eq Bit
(Use FlexibleContexts to permit this)

{-# LANGUAGE FlexibleContexts #-} doesnt work either. {-# LANGUAGE FlexibleContexts #-} 也不起作用。

You make use of x == Zero , so of the (==):: Eq a => a -> a -> Bool function, but you did not make Bit an instance of Eq .您使用了x == Zero ,因此使用了(==):: Eq a => a -> a -> Bool function,但您没有使Bit成为Eq的实例。 You can do so by adding it to the deriving clause, such that Haskell can automatically implement an instance of Eq for your Bit data type:您可以通过将其添加到deriving子句来实现,这样 Haskell 可以为您的Bit数据类型自动实现Eqinstance

data Bit = One 
         | Zero
         deriving (Eq, Show)

By default two items are the same if the data constructor is the same, and the parameters (but here your data constructors have no parameters, so it will only check equality of the data constructors).默认情况下,如果数据构造函数和参数相同,则两项相同(但这里您的数据构造函数没有参数,因此它只会检查数据构造函数的相等性)。

That being said, you do not need these to be an instance of Eq , you can use pattern matching instead.话虽如此,您不需要这些是Eq的实例,您可以使用模式匹配来代替。 Indeed:的确:

bits2String :: Bits -> String
bits2String = map f
    where f Zero = '0'
          f One = '1'

Here we make use of map:: (a -> b) -> [a] -> [b] to convert a list of items to another list by applying a function to each of the items in the original list.在这里,我们使用map:: (a -> b) -> [a] -> [b]通过将 function 应用于原始列表中的每个项目来将项目列表转换为另一个列表。 Since Bits is a list of Bit s, and String is a list of Char s, we can thus map each Bit to a Char to obtain a String of '0' s and '1' s for the Zero and One s respectively.由于BitsBit的列表,而StringChar的列表,因此我们可以 map 将每个Bit转换为Char以分别获得ZeroOne'0''1'String

The original error message is the key one:原始错误消息是关键:

No instance for (Eq Bit) arising drom a use of '=='

This arises because you are using the == operator, which is only available for instances of the Eq typeclass - and you haven't given such an instance.出现这种情况是因为您使用了==运算符,该运算符仅适用于Eq类型类的实例 - 而您没有给出这样的实例。

That's easily fixed though.不过,这很容易解决。 For one you can easily provide the instance manually:一方面,您可以轻松地手动提供实例:

instance Eq Bit where
    One == One = True
    Zero == Zero = True
    _ == _ = False

I wouldn't recommend that you do that though.我不建议你这样做。 You can ask Haskell to generate that exact instance for you by simply adding a deriving clause to the type definition.您可以要求 Haskell 为您生成确切的实例,只需在类型定义中添加deriving子句即可。 In fact you're already using one, so you can just add Eq to the list of instances you want to derive:事实上,您已经在使用一个,因此您只需将Eq添加到您想要派生的实例列表中:

data Bit = One 
     | Zero
     deriving (Show, Eq) 

Adding this instance is a good idea in general, because you might well need to compare Bit s for equality at some point, especially when working with lists of them - many list functions such as elem depend on Eq instances for their members.通常,添加此实例是一个好主意,因为您可能需要在某些时候比较Bit的相等性,尤其是在处理它们的列表时 - 许多列表函数(例如elem )依赖于Eq实例的成员。

But you can rewrite your bits2String function to not need an Eq instance at all, by pattern matching on the two data constructors:但是您可以通过在两个数据构造函数上进行模式匹配来重写您的bits2String function 根本不需要Eq实例:

bits2String :: Bits -> String
bits2String [] = ""
bits2String (One:xs) = "1" ++ bits2String xs
bits2String (Zero:xs) = "0" ++ bits2String xs

In fact, you've basically reimplemented the map function here, so what I would likely do is to define:实际上,您基本上在这里重新实现了map function,所以我可能会做的是定义:

bitToChar :: Bit -> Char
bitToChar Zero = '0'
bitToChar One = '1'

(especially as it's the kind of general utility function that you may well want for other things) (特别是因为它是一种通用实用程序 function,您可能希望用于其他用途)

and then接着

bits2String = map bitToChar 

None of those require an Eq instance - but it's likely a good idea to derive it anyway, for the reasons I mentioned.这些都不需要Eq实例——但出于我提到的原因,无论如何推导出它可能是个好主意。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM