测试带有负数的函数时键入错误

vam*_*olu 3 haskell literals type-signature

我正在关注Learn you a Haskell for great good,我已经实施了take':

take' :: (Ord i, Num i) => i -> [a] -> [a]
take' n _
  | n <= 0 = []
take' _ [] = []
take' n (x:xs) = x: take' (n-1) xs
Run Code Online (Sandbox Code Playgroud)

测试功能时:

take' -2 [2]
Run Code Online (Sandbox Code Playgroud)

而不是得到一个空列表,我有这样的消息:

Non type-variable argument in the constraint: Num (i -> [a] -> [a])
    (Use FlexibleContexts to permit this)
    When checking that ‘it’ has the inferred type
      it :: forall i a t.
            (Num i, Num t, Num (i -> [a] -> [a]), Num ([t] -> i -> [a] -> [a]),
             Ord i) =>
            i -> [a] -> [a]
Run Code Online (Sandbox Code Playgroud)

我按照建议在-和之间添加了一个空格2,它导致了同样的错误:

*Main> take' - 2 [2]

<interactive>:78:1:
    Non type-variable argument in the constraint: Num (i -> [a] -> [a])
    (Use FlexibleContexts to permit this)
    When checking that ‘it’ has the inferred type
      it :: forall i a t.
            (Num i, Num t, Num (i -> [a] -> [a]), Num ([t] -> i -> [a] -> [a]),
             Ord i) =>
            i -> [a] -> [a]
Run Code Online (Sandbox Code Playgroud)

lef*_*out 5

正如评论中已经讨论过的,这只是解析规则的问题。你的表情take' -2 [2]看起来应该是take' (-2) [2]你想要的。可以说,它应该被解析为这样。事实上,GHC 有一个扩展来实现这种行为:

GHCi, version 7.10.2: http://www.haskell.org/ghc/  :? for help
Prelude> :set -XNegativeLiterals 
Prelude> take -2 [2]
[]
Run Code Online (Sandbox Code Playgroud)

然而,默认情况下,Haskell 总是首先尝试将所有运算符(包括 )解析-为中缀运算符。在上面的表达式中,-左边和右边都有东西(尽管间距不一致,但被忽略了),所以没有-XNegativeLiteralsthis 最终会被解析为(take) - (2 [2]),这意味着完全不同的东西。真的这完全是假的,正如错误消息以一种非常神秘的方式暗示的那样:它想要Num (i -> [a] -> [a]),即它发现您的代码需要将函数(即,take)视为数字(即,作为减法运算符的参数)。

几乎总是当您看到包括需求在内的错误时Num (Some Compound Type),意味着在解析级别已经完全错误。