- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我目前正在学习 Haskell,我对以下内容感到好奇:
如果我向 Haskell 中的列表添加一个元素,Haskell 将返回一个(完全?)新列表,并且不会操作原始列表。
现在假设我有一个包含一百万个元素的列表,并且我在末尾添加了一个元素。 Haskell 是否“复制”整个列表(100 万个元素)并将该元素添加到该副本中?或者幕后是否有一个巧妙的“技巧”来避免复制整个列表?
如果没有“技巧”,复制大型列表的过程是否不像我想象的那么昂贵?
最佳答案
这是一个令人惊讶的复杂问题,因为 Haskell 和 GHC 的两个特性:
列表融合意味着在某些情况下,GHC 可以将列表处理代码重写为不分配列表单元的循环。因此,根据使用的上下文,相同的代码可能不会产生额外的成本。
惰性求值意味着如果一个操作的结果没有被消耗,那么你就不需要支付计算它的成本。例如,这很便宜,因为您只需构造列表的前十个元素:
example = take 10 ([1..1000000] ++ [1000001])
事实上,在该代码中,take 10
可以与列表追加融合,因此它与 [1..10]
相同。
但是我们假设我们正在使用我们创建的所有列表的所有元素,并且编译器没有融合我们的列表操作。现在回答您的问题:
If I add an element to a List in Haskell, Haskell returns a (completly?) new list, and doesn't manipulate the original one. Now let's say I have a List of a million elements and I append one element at the end. Does Haskell "copy" the whole list (1 million elements) and adds the element to that copy? Or is there a neat "trick" going on behind the scenes to avoid copying the whole list?
存在避免复制整个列表的技巧,但通过 append 到其末尾,您可以击败它们。需要理解的是,函数式数据结构通常被设计为“修改”它们的操作将利用结构共享来尽可能多地重用旧结构。例如, append 两个列表可以这样定义:
(++) :: [a] -> [a] -> [a]
[] ++ ys = ys
(x:xs) ++ ys = x : xs ++ ys
查看此定义,您可以看出列表 ys
将在结果中重用。因此,如果我们有 xs = [1..3]
、ys = [4..5]
和 xs++ ys
,全部完全立即评估并保留在内存中,从内存角度来看,它看起来像这样:
+---+---+ +---+---+ +---+---+
xs = | 1 | -----> | 2 | -----> | 3 | -----> []
+---+---+ +---+---+ +---+---+
+---+---+ +---+---+
ys = | 4 | -----> | 5 | -----> []
+---+---+ +---+---+
^
|
+------------------------------------+
|
+---+---+ +---+---+ +---+---+ |
xs ++ ys = | 1 | -----> | 2 | -----> | 3 | -------+
+---+---+ +---+---+ +---+---+
这就是长话短说:如果你执行xs++ ys
,并且它没有融合,并且你消耗了整个列表,那么这将创建的副本>xs
但将内存重用于ys
。
但是现在让我们再看看你的问题:
Now let's say I have a List of a million elements and I append one element at the end. Does Haskell "copy" the whole list (1 million elements) and adds the element to that copy?
这将类似于 [1..1000000]++ [1000001]
,是的,它会复制整整一百万个元素。但另一方面,[0]++ [1..1000000]
只会复制[0]
。经验法则是这样的:
解决此类问题的一般方法是:
关于Haskell 中的列表操作性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30261346/
如标题所示,ans_list是一个答案列表,ans_index是一个数字(答案在词汇表中的索引,但与atm无关) 这里生成的 tree.anslist 是什么? (例如,仅针对第一个),忽略迭代。 f
我目前将用户的输入存储在逗号分隔的列表中,如下所示: Userid | Options 1 | 1,2,5 用户在一个数组形式中勾选一组选项,然后用逗号连接起来 1,2,5 然后 MySQ
我目前将用户的输入存储在逗号分隔的列表中,如下所示: Userid | Options 1 | 1,2,5 用户在一个数组形式中勾选一组选项,然后用逗号连接起来 1,2,5 然后 MySQ
我想知道如何完全展平列表和包含它们的东西。除其他外,我想出了一个解决方案,它可以将具有多个元素的东西滑倒并将它们放回原处,或者在滑倒后将具有一个元素的东西拿走。 这与 How do I “flatte
我想知道如何完全展平列表和包含它们的东西。除其他外,我想出了一个解决方案,它可以将具有多个元素的东西滑倒并将它们放回原处,或者在滑倒后将带有一个元素的东西拿走。 这与 How do I “flatte
这个问题已经有答案了: Convert nested list to 2d array (3 个回答) 已关闭 7 年前。 java中有没有快捷方式可以转换 List> 到 String[][] ?
我在排序时遇到问题 List> 。我创建了一个自定义比较器,在其中编写了对数据进行排序的代码。 public class CustomComparator implements Comparator
这个问题已经有答案了: 已关闭10 年前。 Possible Duplicate: Java Generics: Cannot cast List to List? 我只是想知道为什么下面的java代
试图想出一个 LINQy 方法来做到这一点,但我什么也没想到。 我有一个对象列表<>,其中包含一个属性,该属性是逗号分隔的字母代码列表: lst[0].codes = "AA,BB,DD" lst[1
假设我有这些任务: points = [] point = (1, 2) 我怎么会这样做: points += point 它工作得很好,并且给了我点 = [1, 2]。但是,如果我这样做: poin
如何在 scala 中将 List[Task[List[Header]]] 类型转换为 Task[List[Header]]。 我有一个方法返回 Task[List[Header]] 并多次调用 do
如何在 Java 中查找二维列表的元素? 我有一个参数为 List> 的函数我想知道如何找到这个列表的行和列。 最佳答案 如果你喜欢 List> obj 然后你就可以像这样访问 obj.get(cur
分配 List到 List工作正常。 分配 List>到 List>不编译。 代码 public class Main { public static void main(String[] a
我正在用 Java 编写一个方法,该方法必须接收并迭代 Serializable 的 List。 有什么区别: public void myMethod(List list) { } 和 public
我看到很多人想用 mvvm 更新网格/列表/树的一部分,但他们不想刷新整个列表。 对于所有遇到此问题的人,我做了以下示例。 希望这对你有用。 最佳答案 这是一个简单的例子。整个代码中最重要的是: Bi
我正在为现有的 C++ 库编写包装器,该库使用列表,其中 T 是自定义结构。我被建议使用 vector 而不是列表,但我试图避免修改库。 为了更好地理解这个场景,我做了一个简单的应用程序,使用一个列表
List list List list 这两种声明有什么区别吗? 谢谢, 最佳答案 是的。 List可以包含所有派生自 Base 的不同事物的混合物. List包含同质项(从某种意义上说,它们必须全部
有人可以尽可能详细地解释以下类型之间的区别吗? List List List 让我更具体一点。我什么时候想使用 // 1 public void CanYouGiveMeAnAnswer(List l
我有一个元组列表,每个元组都是一对列表。所以我的数据看起来像: mylist = [(['foo', 'bar'], ['bar', 'bar']),(['bar', 'bar'],['bar', '
也许是一个时髦的标题,但我遇到了以下问题: 给定一个类型为 (a * b) list 的列表,我想创建一个类型为 (a * b list) list 的新列表。一个例子: 给定列表 let testL
我是一名优秀的程序员,十分优秀!