Haskell 通过去除污垢来提高效率

Haskell 通过去除污垢来提高效率,haskell,Haskell,我试图提高代码中某个特定函数的效率,该函数占用了大量运行时。在分析之后,我相信这是因为代码中的concat。我怎样才能改进这段代码以更快 chunk :: C -> [A] -> [[A]] chunk c = go [] where s = Set.fromList (map snd (Map.toList c)) go :: [A] -> [A] -> [[A]] go l [] = [l | member l s]

我试图提高代码中某个特定函数的效率,该函数占用了大量运行时。在分析之后,我相信这是因为代码中的concat。我怎样才能改进这段代码以更快

chunk :: C -> [A] -> [[A]]
chunk c = go []
  where s = Set.fromList (map snd (Map.toList c))
        go :: [A] -> [A] -> [[A]]
        go l []     = [l | member l s]
        go l (x:xs) = if member l s then l : go [x] xs
                                    else go (l ++ [x]) xs

谢谢你的帮助

一个简单的解决方案是使用,其中snoc操作是O(1)。这涉及到先转换输入,然后再转换回结果,这是值得的,除非集合比列表的平均长度大

然而,还有另一个问题,那就是测试列表(或类似结构)的成员资格。列表上的比较或测试相等性是O(n),在您的情况下,如果您测试一个列表的成员资格,该列表很可能是集合中包含的列表的子列表,那么测试将确实是Ω(n)。因此,即使如此,
chunk
的复杂度也可能是O(n^2),其中n是列表参数的长度

似乎使用a将是一个更好的解决方案。在内存和时间复杂度方面,trie比一组列表更有效。对于这种情况特别有用的是它的操作,它允许您通过过滤O(1)中具有给定前缀的所有元素来构造一个子trie

示例代码(未测试):

现在,
go
的每一步应该只取O(n)摊销成本(唯一的非O(1)操作是
reverse
,但这是O(1)摊销,因为k元素列表在k步之后只发生一次反转)

现在我们还可以做进一步的改进:当sub-trie为空时,我们知道我们永远不会返回额外的元素,因为我们永远不会到达匹配的大小写。所以我们可以在顶部添加图案

        go s _ _ | Trie.null s = []

这个软件包似乎正适合于此。

一个简单的解决方案是使用,其中snoc操作是O(1)。这涉及到先转换输入,然后再转换回结果,这是值得的,除非集合比列表的平均长度大

然而,还有另一个问题,那就是测试列表(或类似结构)的成员资格。列表上的比较或测试相等性是O(n),在您的情况下,如果您测试一个列表的成员资格,该列表很可能是集合中包含的列表的子列表,那么测试将确实是Ω(n)。因此,即使如此,
chunk
的复杂度也可能是O(n^2),其中n是列表参数的长度

似乎使用a将是一个更好的解决方案。在内存和时间复杂度方面,trie比一组列表更有效。对于这种情况特别有用的是它的操作,它允许您通过过滤O(1)中具有给定前缀的所有元素来构造一个子trie

示例代码(未测试):

现在,
go
的每一步应该只取O(n)摊销成本(唯一的非O(1)操作是
reverse
,但这是O(1)摊销,因为k元素列表在k步之后只发生一次反转)

现在我们还可以做进一步的改进:当sub-trie为空时,我们知道我们永远不会返回额外的元素,因为我们永远不会到达匹配的大小写。所以我们可以在顶部添加图案

        go s _ _ | Trie.null s = []

软件包似乎非常适合这种情况。

选择一个带有O(1)snoc和cons的结构。我认为数据列表和序列对你来说应该很有趣。嗯,很有趣。我看了一下DList模块,但是我很难弄清楚如何在它们上进行模式匹配。可能吗?或者我应该重写代码的这一部分吗?然后调用toList以保留旧的api。还有一个“穷人队列”可能在这里工作得很好:
键入Q a=([a],[a])
。Cons'd元素按相反顺序在左边,snoc'd元素按相反顺序在右边。您可以使用
toList(xs,ys)=xs++reverse ys
一次完成所有昂贵的snoc。丹尼尔·瓦格纳建议的“穷人出列”可能相当不错。您应该能够使用
fromscendinglist
或任何它的名称,更快地将
Map
转换为
Set
。甚至可能有一种更快的方法,根据
映射的大小,最好跳过转换,只在
映射中查找元素。我认为数据列表和序列对你来说应该很有趣。嗯,很有趣。我看了一下DList模块,但是我很难弄清楚如何在它们上进行模式匹配。可能吗?或者我应该重写代码的这一部分吗?然后调用toList以保留旧的api。还有一个“穷人队列”可能在这里工作得很好:
键入Q a=([a],[a])
。Cons'd元素按相反顺序在左边,snoc'd元素按相反顺序在右边。您可以使用
toList(xs,ys)=xs++reverse ys
一次完成所有昂贵的snoc。丹尼尔·瓦格纳建议的“穷人出列”可能相当不错。您应该能够使用
fromscendinglist
或任何它的名称,更快地将
Map
转换为
Set
。甚至可能有一种更快的方法,根据
映射的大小,最好跳过转换,只在
映射中查找元素。