Haskell:了解 ghci 中的“No instance for”错误消息

Haskell : understanding "No instance for" error messages in ghci

提问人:artella 提问时间:4/30/2012 最后编辑:ulidtkoartella 更新时间:11/20/2014 访问量:13922

问:

第1项质询

嗨,如果在 WinGHCi 中,我故意执行以下错误的代码:

3 4

然后我得到的错误消息是

<interactive>:1:1:
    No instance for (Num (a0 -> t0))
      arising from the literal `3'
    Possible fix: add an instance declaration for (Num (a0 -> t0))
    In the expression: 3
    In the expression: 3 4
    In an equation for `it': it = 3 4

这究竟意味着什么?No instance for (Num (a0 -> t0))

第2项质询

为什么下面这段代码:

(+) 2 3 4
<interactive>:1:7:
    No instance for (Num (a0 -> t0))
      arising from the literal `3'
    Possible fix: add an instance declaration for (Num (a0 -> t0))
    In the second argument of `(+)', namely `3'
    In the expression: (+) 2 3 4
    In an equation for `it': it = (+) 2 3 4

产生与第二段代码略有不同的错误:

2+3 4
<interactive>:1:3:
    No instance for (Num (a1 -> a0))
      arising from the literal `3'
    Possible fix: add an instance declaration for (Num (a1 -> a0))
    In the expression: 3
    In the second argument of `(+)', namely `3 4'
    In the expression: 2 + 3 4

也就是说,在第一段代码中,我们有,在第二段代码中,我们有.No instance for (Num (a0 -> t0))No instance for (Num (a1 -> a0))


[对 ehird 的回应]

(问题从回答评论中移出):

1)我很欣赏后两种表达方式的不同,但你是说我不应该试图理解为什么口译员选择前者而选择后者,除了它们不同这一事实之外?(Num (a0 -> t0))(Num(a1 -> a0))

2)嗨,对于前者,当您说“但是函数没有 Num 实例”时,您的意思是什么?对不起,我不清楚实例的概念是什么。此外,出于好奇,你能不能用你的实例方法以某种方式告诉解释器解释为?Num (a -> b)3 44 modulo 3

Haskell GHC GHCI 翼HCI

评论


答:

14赞 ehird 4/30/2012 #1

第一个错误的发生是因为整数文字 like 可以是具有实例的任何类型。也就是说,具有类型,因此它可以用作 、 、 a 等。由于您应用了参数 (),因此它知道在上下文中必须是函数类型(即 对于某些和)。但是没有函数的实例,因此将 as 用作函数是无效的。如果您添加了 ,它会起作用,但您可能不想这样做。4Num4(Num a) => aIntegerDoubleRational343a0 -> t0a0t0Num3instance Num (a -> b)

至于后者,两条错误消息是等效的;GHC生成的名称没有特别的含义。这些字母通常派生自您正在使用的函数类型中的类型变量,并附加数字以保持明确。在本例中,第二个表达式等效于(因为函数应用程序比任何中缀运算符绑定得更紧密),这与第一段代码并不完全相同。(+) 2 (3 4)

评论

0赞 artella 4/30/2012
嗨,我很欣赏后两种表达方式的不同,但你是说我不应该试图理解为什么口译员选择前者而选择后者,除了它们不同这一事实之外?谢谢。(Num (a0 -> t0))(Num(a1 -> a0))
0赞 artella 4/30/2012
嗨,对于前者,当您说“但是函数没有 Num 实例”时,您的意思是什么?对不起,我不清楚实例的概念是什么。此外,出于好奇,你能用你的方法以某种方式告诉解释者解释为“4 模 3”吗?谢谢instance Num (a -> b)3 4
16赞 Chris Taylor 4/30/2012 #2

我的目的是用更多的解释来补充 ehird 的回答。当你写表达式时

3 4

然后 Haskell 解释器认为您正在尝试将该函数应用于任何事物。为了让 Haskell 解释为一个函数,它需要调用该函数343

fromInteger :: Integer -> (a -> b)

为了从整数中获取函数(即类型的东西)。现在,在类型类中定义为具有签名a -> b3fromIntegerNum

instance Num x where
    fromInteger :: Integer -> x

也就是说,当你使类型成为类的实例时,你给出了一个实现,它告诉Haskell如何将整数文字转换为.在您的例子中,是函数类型。所以让我们开始吧!xNumfromIntegerxxa -> b


首先,一些样板。要创建 Haskell 的实例,还需要将其作为 和 的实例:xNumShowEq

instance Show (a -> b) where show f = "<function>"
instance Eq (a -> b) where f == g = False

现在假设我们想解释为“4 模 3”。然后我们需要告诉 Haskell 如何将任何整数解释为调用 .此外,由于只接受整型(它有签名),那么我们还需要限制 和 的类型:3 4modmodmod :: Integral a => a -> a -> aab

instance (Integral a, Integral b) => Num (a -> b) where

创建 Num 的实例,我们需要给出 、 和 的实现(实际上我们也应该定义几个其他函数,但现在我们不用担心)。(+)(-)(*)fromIntegral

有一种相当自然的方法来定义加法、减法和乘法(此处的所有代码都构成实例的一部分,并且应该相对于实例声明缩进)Num

    f + g = \x -> f x + g x
    f - g = \x -> f x - g x
    f * g = \x -> f x * g x

即,当您添加两个函数 和 时,您将得到一个新函数,该函数同时应用于其参数,然后将它们相加。由于我们要求应用 and 的结果是整型的,因此我们知道将它们的输出相加是有意义的。fgfgfg

要将整数解释为函数,我们可以编写

    fromInteger n = \m -> fromIntegral m `mod` fromIntegral n

即当我们有一个整数时,我们返回一个参数的函数,该函数在调用时确保两个参数属于同一类型(通过调用它们),然后将它们用作函数的参数。nmfromIntegralmod

最后,再多一点样板来阻止 Haskell 抱怨:

    abs f = undefined
    signum f = undefined

我们可以对此进行测试。我的代码在一个名为numfun.hs的文件中。我启动Haskell解释器并加载我的文件:

Prelude> :l numfun.hs
[1 of 1] Compiling Main             ( numfun.hs, interpreted )
Ok, modules loaded: Main.

现在我可以定义一些函数:

*Main> let f = (+ 1)
*Main> let g = (* 2)

我可以添加或减去它们:

*Main> (f + g) 3   -- (3+1) + (3*2)
10
*Main> (f - g) 3   -- (3+1) - (3*2)
-2

我可以将数字称为函数:

*Main> 3 4         -- 4 `mod` 3
1

评论

0赞 artella 4/30/2012
哇,非常感谢您提供详细且概述良好的解释;我真的很感激。我想我需要阅读 Haskell 网站上指定的一些书籍,并在消化您写的所有内容之前再返回您的帖子几次。谢谢。