我的代码可以工作,但不能处理无尽的列表。我如何才能让它工作?
sumsOf :: Num a => [[a]] -> [a]
sumsOf a = map sum [ x | x <- a , length x < 3]
示例:
sumsOf [[],[1,2,4],[],[6]] == [0,0,6]
sumsOf [[1],[8],[6],[],[9,9]] == [1,8,6,0,18]
sumsOf [[1,2,9,10],[7,8,9],[6,9,4,2,0],[9,9,9]] == []
sumsOf [[1..],[7..],[6..],[9..],[10..],[100..]] == []
sumsOf [[1,2], [1..], [], [4]] == [3,0,4]
2条答案
按热度按时间c3frrgcw1#
length
是列表函数之一,作为经验法则,您应该永远不要使用它,除非您确切地知道它为什么可以使用。(另一个是head
和!!
。)这不仅仅是因为它不能处理无限列表,也是因为它做了一个通常完全不必要的(n)遍历整个列表。即使你以后无论如何都要遍历它,做两次也会带来很大的性能差异。在这种情况下,想想你真正需要的是什么:一个
sum
,它避免进入一个长的或无限的列表,而是在两个元素之后放弃。这实际上可以用一种愚蠢的穷举方法来实现:要使它对任何max-length都通用,可以使用递归:
...但这并不是一个很好的实现,原因有二:它会因为负参数而崩溃,而且它不是尾递归的。
更优雅的做法是使用一个标准函数来获取元素的最大可用计数,并查看是否还有剩余:
...或一些等效形式,
或
然后,您可以将其Map到整个给定的列表,并收集所有成功的结果。
fjaof16o2#
简单懒惰的解决方案:
您只关心长度是否小于3,因此如果您将输入列表截断为3个元素,结果不会更改:
因此,这很容易解决无限列表的问题。
以稍微更惯用的方式:
唯一的缺点是库函数
take
必须复制列表节点。在n.1.8e9的评论中提到了一个想法--我的共享在哪里:通过编写一些
boundedLength
函数,最多返回k
,可以得到更有效的结果,例如:在这种情况下,我们的
sumsOf
函数的结果为: