Haskell中[1 .. 0]与[1 .. -1]的区别和原因是什么?

时间:2014-11-23 16:24:38

标签: haskell list-comprehension range-notation

我定义了以下功能

let repl x n = [x | _ <- [1..n]]

它模仿内置的复制功能。

在尝试使用它时,我注意到一个奇怪的事情:repl 10 0评估为[],而repl 10 -1产生错误:

No instance for (Show (t10 -> [t0])) arising from a use of ‘print’
In a stmt of an interactive GHCi command: print it

另一方面,[1 .. 0][1 .. -1]评估为[]而不会产生任何错误。

此外,[42 | _ <- [1 .. 0]][42 | _ <- [1 .. -1]]评估为[]且没有错误。

那么为什么我的函数调用会导致显式替换不出错的错误?更重要的是,[1 .. 0][1 .. -1]之间的明显差异源自何处?

最后一个问题:我写的时候:

repl 42 -1

错误与repl 10 -1完全相同,即它仍然包含(Show (t10 -> [t0]))位。我期待它有像((Show (t42 -> [t0])))这样的东西。这是什么10?

3 个答案:

答案 0 :(得分:4)

其他答案指出您需要将-1括在括号中。这是an odd corner of the Haskell 98 spec,意外地跳出来咬。如果你不能在没有括号的情况下写下负数:-1 * 5没问题。只是一元前缀运算符的优先级不高于二进制中缀运算符,因此-经常被解析为后者。运算符周围的空格在Haskell中并不重要。

难以理解的类型类错误并没有帮助。顺便提一下,t10t0只是编译器构成的占位符类型变量;我不认为它与您使用的实际数字文字有任何关系。非正式地,像Could not deduce (Num (a0 -> t))这样的错误通常告诉我,一个函数适用于太少的参数。

或者,GHC 7.8中的(未记录的?)NegativeLiterals语言扩展更改了-1的含义以解决此问题。

> :set -XNegativeLiterals
> :t repl 10 -1
repl 10 -1 :: Num t => [t]

答案 1 :(得分:2)

您的问题中未包含 完整 错误消息,如果有,您会看到repl 10 -1被解析为{{1这不是你想要的。

(repl 10) - (1)会出现同样的错误。

通过仔细查看错误消息,您经常可以找到解析程序代码的线索。在你学习的同时,过度使用括号也没有坏处。

The program

repl 10 +1

消息:

prog.hs:3:8:
    No instance for (Show (t1 -> [t0])) arising from a use of `print'
    Possible fix: add an instance declaration for (Show (t1 -> [t0]))
    In the expression: print (repl 10 - 1)
    In an equation for `main': main = print (repl 10 - 1)

prog.hs:3:15:
    No instance for (Num t1) arising from a use of `repl'
    The type variable `t1' is ambiguous
    Possible fix: add a type signature that fixes these type variable(s)
    Note: there are several potential instances:
      instance Num Double -- Defined in `GHC.Float'
      instance Num Float -- Defined in `GHC.Float'
      instance Integral a => Num (GHC.Real.Ratio a)
        -- Defined in `GHC.Real'
      ...plus three others
    In the first argument of `(-)', namely `repl 10'         --------- NB!
    In the first argument of `print', namely `(repl 10 - 1)'
    In the expression: print (repl 10 - 1)

prog.hs:3:20:
    No instance for (Num t0) arising from the literal `10'
    The type variable `t0' is ambiguous
    Possible fix: add a type signature that fixes these type variable(s)
    Note: there are several potential instances:
      instance Num Double -- Defined in `GHC.Float'
      instance Num Float -- Defined in `GHC.Float'
      instance Integral a => Num (GHC.Real.Ratio a)
        -- Defined in `GHC.Real'
      ...plus three others
    In the first argument of `repl', namely `10'
    In the first argument of `(-)', namely `repl 10'         --------- NB!
    In the first argument of `print', namely `(repl 10 - 1)'

prog.hs:3:23:
    No instance for (Num (t1 -> [t0])) arising from a use of `-'
    Possible fix: add an instance declaration for (Num (t1 -> [t0]))
    In the first argument of `print', namely `(repl 10 - 1)'
    In the expression: print (repl 10 - 1)
    In an equation for `main': main = print (repl 10 - 1)

答案 2 :(得分:1)

你试过[1..(-1)]吗?在Haskell中,你不能直接写出-1这样的负数。你需要将它们放在括号中。原因是Haskell没有前缀一元运算符,因为Haskell中的运算符总是中缀。因此,-1被解析为[operator (-)] [numeric 1]而不是[numeric -1]

这是导致问题的原因。为避免此问题,必须将负数放在括号中。这可确保(-1)被解析为[numeric -1]。它是为数不多的能够在Haskell为新移民提供偏头痛的角落病例之一。