我正在尝试理解haskell错误消息,因为它们让新手程序员感到困惑。我能找到的最简单的例子是:
Prelude> 1 + True
<interactive>:2:3:
No instance for (Num Bool)
arising from a use of `+'
Possible fix: add an instance declaration for (Num Bool)
In the expression: 1 + True
In an equation for `it': it = 1 + True
为什么编译器会查找(Num Bool)而不管参数顺序如何?为什么在定义以下内容后它会起作用?
instance Num Bool where (+) a b = True;
[...]
Prelude> 1 + True
True
如果第二个参数也是(Num Bool),我怎样才能确保(+)可以应用于(Num Bool) ?
答案 0 :(得分:4)
您收到此错误消息是因为1
和+
都是多态的 - 它们都适用于不同的类型!
看看:
Prelude> :t 1
1 :: Num a => a
Prelude> :t (+)
(+) :: Num a => a -> a -> a
因此,1
和 +
对于Num
类中的任何类型都有意义。因此,当您撰写1 + Bool
时,1
可能实际上是Bool
,如果Bool
有Num
个实例。事实上,你可以自己做:
instance Num Bool where
fromInteger x = x /= 0
(+) = (&&)
...
执行此操作后,1 + True
实际上会有效。您还可以使用数字文字作为bools:
*Main> 1 :: Bool
True
*Main> 1 + True
True
这也解释了为什么无论参数的顺序如何都会得到相同的错误:代码中唯一的实际问题是True
- 如果有效,其他一切也都会出现。
答案 1 :(得分:1)
Num的合同是任何数字整数都可以转换为所需的类型。
通过你的声明,Haskell试图实现:
fromIntegral 1 + True
可能用第一个参数undefined调用你的布尔值(+)。但这没关系,因为你从不评价它。
尝试这样写:
(+) a b = if a then True else False
你可能会看到错误。
答案 2 :(得分:0)
如果您在data Bool
以下命令中运行,则错误消息表明class Num
不是ghci
的实例
Prelude> :info Num
class Num a where
(+) :: a -> a -> a
(*) :: a -> a -> a
(-) :: a -> a -> a
negate :: a -> a
abs :: a -> a
signum :: a -> a
fromInteger :: Integer -> a
-- Defined in `GHC.Num'
instance Num Integer -- Defined in `GHC.Num'
instance Num Int -- Defined in `GHC.Num'
instance Num Float -- Defined in `GHC.Float'
instance Num Double -- Defined in `GHC.Float'
您可以看到Num
可以添加(+)
,乘以(*)
,减去(-)
等等。
由于Bool
的行为不能如此,因此它没有Num
的实例。这解释了错误No instance for (Num Bool)
中的行,因为(+)
只能用于Num
的实例
您在instance Num Bool where (+) a b = True
中所做的是说现在Bool
的行为也类似于Num
,因此您必须指定如何添加Bool
{{} 1}},乘以(+)
等等。
我希望我能以一种简单的方式解释。