【问题标题】:Haskell function argument type inference with typeclassesHaskell 函数参数类型推断与类型类
【发布时间】:2013-11-10 18:08:59
【问题描述】:

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

【问题讨论】:

    标签: haskell types pattern-matching typeclass


    【解决方案1】:

    Num 的约定是任何数字整数文字都可以转换为所需的类型。

    有了你的声明,Haskell 在现实中尝试:

    fromIntegral 1 + True
    

    这可能会调用您的布尔值 (+),而第一个参数未定义。但这没关系,因为你从不评估它。

    试着这样写:

    (+) a b = if a then True else False
    

    你可能会看到一个错误。

    【讨论】:

      【解决方案2】:

      错误信息是说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 添加(+)、乘以(*) 等.

      我希望我解释得足够简单。

      【讨论】:

      • Bool 绝对可以“表现得像这样”(instance Num Bool where { (+)=(||);(*)=(&amp;&amp;);negate=not;abs=id;signum=id;fromInteger=(/=0) }),只是定义一个Num 实例不是很明智,因为它允许更多的程序员错误成为不被类型系统注意到。
      • @Rhymoid:旁注——(+) 最好定义为异或,这样你就得到了一个布尔环。
      【解决方案3】:

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

      看看:

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

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

      instance Num Bool where
        fromInteger x = x /= 0
        (+) = (&&)
        ...
      

      一旦你这样做了,1 + True 就会真正起作用。您还可以将数字文字用作布尔值:

      *Main> 1 :: Bool
      True
      *Main> 1 + True
      True
      

      这也解释了为什么无论参数的顺序如何都会出现相同的错误:代码中唯一的实际问题是True--如果它有效,那么其他所有东西也会。

      【讨论】:

      • @Rumca 正如您从这个答案中看到的那样,您已经确保两个参数都必须是Bool。让你感到困惑的是,当你在 Haskell 源文件中键入值 1 时,GHC 会隐式地将其放入 fromInteger 调用中,这意味着 1 不一定是整数,而是可以转换为几乎任何编译程序时键入。你可以自己测试一下——问 ghci \n -&gt; n + True 的类型是什么。它会说n 必须是Bool
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-08-28
      • 1970-01-01
      • 1970-01-01
      • 2012-11-21
      • 1970-01-01
      • 2016-11-01
      • 1970-01-01
      相关资源
      最近更新 更多