Haskell令人惊讶的功能签名

时间:2015-10-08 03:14:35

标签: haskell

我是Haskell的新手,请原谅我提出这个可能很明显的问题,但我对此感到惊讶:

len2 :: [a] -> Int
len2 xx = if xx == [] then 0 else 1 + (len2 (tail xx))

给了我:

No instance for (Eq a) arising from a use of ‘==’
Possible fix:
  add (Eq a) to the context of
    the type signature for len2 :: [a] -> Int
In the expression: xx == []

我很惊讶,因为我认为Haskell可以在不查看任何元素的情况下判断列表是否为[](在C ++中,我会看到列表的大小为0,并将其留在那里,例如) 。

1 个答案:

答案 0 :(得分:9)

在这种情况下,(==)的类型为Eq a => [a] -> [a] -> Bool。希望你同意在看到任何参数之前Eq a约束是有意义的:如果你想检查两个任意列表是否相等,你必须知道如何检查元素是否相等。您可能希望,一旦您将(==)应用于具体参数[],则不需要Eq a约束,但实际上这是一个非常微妙的注意事项。也许部分评估可以产生没有约束的函数。但是现存的实现并没有尝试进行这种分析;他们保留了保守类型Eq a => [a] -> Bool,它已经排除了[a]个参数,但没有Eq a约束。

一些选项:

  1. 使用null :: [a] -> Bool代替(==[])

    len2 xx = if null xx then ... else ...
    
  2. 模式匹配,因此:

    len2 []     = ...
    len2 (x:xs) = ...
    

    作为奖励,这样您就可以避免调用讨厌的tail函数。

  3. 我会说选择(2)明显更具惯用性。