带类型类的Haskell函数参数类型推断

时间:2013-10-30 21:59:16

标签: haskell types pattern-matching typeclass

我正在尝试理解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)

3 个答案:

答案 0 :(得分:4)

您收到此错误消息是因为1+都是多态的 - 它们都适用于不同的类型!

看看:

Prelude> :t 1
1 :: Num a => a
Prelude> :t (+)
(+) :: Num a => a -> a -> a

因此,1 +对于Num类中的任何类型都有意义。因此,当您撰写1 + Bool时,1 可能实际上是Bool,如果BoolNum个实例。事实上,你可以自己做:

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}},乘以(+)等等。

我希望我能以一种简单的方式解释。