F# 列表是不是持久?
Posted
技术标签:
【中文标题】F# 列表是不是持久?【英文标题】:Are F# lists persistent?F# 列表是否持久? 【发布时间】:2011-08-09 21:29:44 【问题描述】:我是 F# 的新 C# 开发人员,我知道在 .net 中字符串是不可变的。换句话说,每次你修改一个字符串,你都会得到一个新的字符串实例。
对于像我这样的非功能性思维,第一个问题是效率,我知道 C# 可变对象不是持久的。因为字符串操作在大多数应用程序中通常是微不足道的。
我的问题是,F# 列表也是这种情况吗? F# 是否会在更改时克隆每个列表?例如,在过滤列表时,我是否会创建一个包含更少项目的新列表?
更新:我不是在比较 .net 字符串和列表。我将字符串命名为不可变对象的示例,并想知道 F# 是否为它的 List 提供任何特殊处理。
这就是我所说的“persistent”。
【问题讨论】:
.Net 字符串是不可变的,它与 C# 无关。 C#、VB.Net 和任何其他 .Net 语言都将具有不可变字符串,因为它是相同的代码库,并且最终是相同的 IL,而与语言无关。 抱歉,我编辑了标题,因为不可变数据结构是通常应用于函数式编程列表、地图等的术语,而持久对象有数据库意义上的第二个含义。 我同意,但这是数据结构实现术语中的标准术语。 虽然我完全理解您的好奇心。效率应该是您编写代码时最不担心的事情。您可以重新实现运行速度是原始速度两倍的东西,但它可以同时在 4 个处理器上运行。它现在的速度是原来的两倍。 我完全同意,但最好知道幕后发生的事情。 【参考方案1】:我认为 Dustin Campbell's introduction 在解释列表不变性方面做得非常出色。
在函数世界中,列表是不可变的。这意味着节点共享是可能的,因为原始列表永远不会改变。因为第一个列表以空列表结尾,所以必须复制其节点以将其最后一个节点指向第二个列表。追加操作后,我们的列表如下所示:
在这一点上,你们当中越怀疑的人可能会说,“好吧, 这是一个非常有趣的理论,但你能证明它吗?”
没问题。
利用 F# 列表是递归的知识,我们可以检索 组合的后半部分(从 4 开始的内部列表) 尾巴,它的尾巴,它的尾巴。 List.tl 是 F# 的函数 用于提取列表的尾部。
> let lastHalf = List.tl (List.tl (List.tl combined));; val lastHalf : int list > lastHalf;; val it : int list = [4; 5; 6]
最后,因为 F# 是 .NET Framework 的一等公民,我们 拥有对所有基类库的完全访问权限。所以,我们可以使用
Object.ReferenceEquals
方法来测试是否lastHalf 和 second 确实是同一个实例。> System.Object.ReferenceEquals(lastHalf, second);; val it : bool = true
你有它。信不信由你,附加两个不可变的 列表实际上比追加更快,内存效率更高 可变列表,因为需要复制的节点更少。
【讨论】:
很遗憾,您提供的链接已失效 :( 使用互联网存档更新建议:web.archive.org/web/20150710063910/http://diditwith.net/2008/03/…【参考方案2】:F# 列表是不可变的。没有用于“修改” F# 列表的 API,因此不涉及克隆。像List.filter
这样的操作确实会创建一个新列表(如果可能,它可能与原始列表共享一些结构)。
(我认为这就是任何语言中所有不可变对象的工作方式。)
参见例如
http://en.wikipedia.org/wiki/Persistent_data_structure
请提供精美的描述以及说明共享工作原理的图片。
【讨论】:
我对“可能分享”部分非常感兴趣。你能解释一下什么时候可以吗? 添加了一篇文章的链接,其中包含有用的漂亮图片。 在列表的情况下,因为它们只是链表,当你追加一个元素时,会创建一个新列表,但实际上只有 head 被设置为指向新值,而 tail 被设置指向现有列表。过滤器和地图等其他操作需要重新创建列表。 明确一点,@emaster 的意思是当你将 cons 和 element 放到列表的前面时,你可以与原始列表共享整个 'tail'。 (附加到列表末尾需要完整副本。)【参考方案3】:我认为 Dan 和 Brian 的参考资料应该直接回答您的问题。如果您想了解更多信息,还可以查看以下材料(本周刚刚在 MSDN 上发布),这些材料旨在向 .NET 开发人员解释 F# 和函数概念:
Tutorial: Working with Functional Lists 介绍了 F# 列表并展示了如何在 C# 中实现相同的概念,这是了解列表如何工作(以及哪些操作有效)的好方法。
Overview: Working with Immutable Data 提供了有关 F# 中不变性的更多背景信息 - 它不会直接回答您的问题,但也可能是一个有用的资源。
【讨论】:
【参考方案4】:F# 列表是链表。因此,当您创建一个新列表时,它只是将项目添加到现有列表并指向包含新项目的头部。原始列表仍然指向在创建该列表时作为头部的项目。所以换句话说,它们都指向列表中不同位置的同一个列表。
【讨论】:
【参考方案5】:用函数式语言理解列表的最佳方法是理解Cons Cells
【讨论】:
以上是关于F# 列表是不是持久?的主要内容,如果未能解决你的问题,请参考以下文章