无法匹配期望的类型`Int'与实际类型[Int]

时间:2014-04-13 04:42:25

标签: haskell

我正在编写一个程序,用于汇总列表的编号:

[2,3,4,5] = 14

编译时出错,我不知道程序想要什么:

getLimit :: [Int] -> Int
getLimit [] = 0
getLimit [x] = sum [x]
getLimit [y:yz] = y + getLimit yz

错误是:

http://i.imgur.com/G06noq4.jpg

感谢您提前提供任何帮助。

2 个答案:

答案 0 :(得分:5)

正如评论中所提到的,您需要在代码中更改一些内容:

  1. [y:yz]表示由于方​​括号而导致的列表列表。您需要将其替换为括号,使其看起来像head:tail模式,如{ - 1}}。
  2. 由于您已经将递归的基本案例定义为(y:yz),因此您可以取消对单个元素列表的测试,并直接转到所有非空列表的列表,使用相同的表达式。
  3. 除此之外,使用getLimit[] = 0可能更好,因为这会使您的代码更短,并具有相同的功能。你可以像这样重写它:

    foldr

    至于为什么我推荐getLimit :: [Int] -> Int getLimit = foldr (\x acc -> x + acc) 0 而不是foldr,我们有很好的解释here

答案 1 :(得分:1)

不,Haskell比Java更容易学习。它没有NullPointerException s。

因此,让我们比较Haskell和Java中的getLimit函数。

的Haskell

getLimit :: [Int] -> Int
getLimit []     = 0
getLimit (x:xs) = x + getLimit xs

getLimit实施的问题在于行getLimit [y:yz] = y + getLimit yz

  1. y:yz的类型为[Int]。因此,[y:yz]的类型为[[Int]],这是错误的。
  2. 编译器告诉你。学习阅读错误消息。你想要的只是(y:yz)
  3. getLimit [x] = sum [x]是不必要的。
  4. 的Java

    public int getLimit(int xs[]) {
        int length = xs.length;
        if (length == 0) return 0;
        else return xs[0] + getLimit(Arrays.copyOfRange(xs, 1, length));
    }
    

    当然在Java中你宁愿使用for循环而不是递归(在我看来更糟糕的是因为循环没有类型,因此编译器无法对其进行类型检查)。

    相比之下,您可以在Haskell中创建类型检查的循环结构。例如,foldl函数定义为:

    foldl :: (b -> a -> b) -> b -> [a] -> b
    foldl _ a []     = a
    foldl f a (x:xs) = foldl f (f a x) xs
    

    这相当于以下JavaScript代码(抱歉,我不知道如何在Java中使用泛型):

    function foldl(f, a, xs) {
        for (var i = 0, l = xs.length; i < xs; i++)
            a = f(a, xs[i]);
        return a;
    }
    

    简而言之,我们给出了for循环类型的特定用例。

    结论

    Haskell比Java好多了。 Haskell的最佳功能之一是泛型。例如,我们可以使getLimit成为适用于所有类型数字的通用函数(不仅仅是Int s):

    getLimit :: Num a => [a] -> a
    getLimit []     = 0
    getLimit (x:xs) = x + getLimit xs
    

    我们唯一改变的是函数的类型签名。其他一切都保持不变。尝试用Java做同样的事情。