我正在编写一个程序,用于汇总列表的编号:
[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
感谢您提前提供任何帮助。
答案 0 :(得分:5)
正如评论中所提到的,您需要在代码中更改一些内容:
[y:yz]
表示由于方括号而导致的列表列表。您需要将其替换为括号,使其看起来像head:tail
模式,如{ - 1}}。(y:yz)
,因此您可以取消对单个元素列表的测试,并直接转到所有非空列表的列表,使用相同的表达式。除此之外,使用getLimit[] = 0
可能更好,因为这会使您的代码更短,并具有相同的功能。你可以像这样重写它:
foldr
至于为什么我推荐getLimit :: [Int] -> Int
getLimit = foldr (\x acc -> x + acc) 0
而不是foldr
,我们有很好的解释here。
答案 1 :(得分:1)
不,Haskell比Java更容易学习。它没有NullPointerException
s。
因此,让我们比较Haskell和Java中的getLimit
函数。
getLimit :: [Int] -> Int
getLimit [] = 0
getLimit (x:xs) = x + getLimit xs
getLimit
实施的问题在于行getLimit [y:yz] = y + getLimit yz
:
y:yz
的类型为[Int]
。因此,[y:yz]
的类型为[[Int]]
,这是错误的。(y:yz)
。getLimit [x] = sum [x]
是不必要的。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做同样的事情。