差异列表
支持O(1)的列表类型追加
和势利小人
操作。
安装
数据清单
Haskell软件包可以从黑客攻击.它可以与一起安装阴谋集团
或堆栈
.
请参阅更改日志针对每个版本中的更改。
用法
下面是一个“展平”a的示例树
到其元素列表中叶子
施工人员:
导入合格数据。DList as DList(作为DList列出)数据树a=叶a|分支(树a)(树a)展平速度慢::树a->[a]展平慢速=开始哪里go(叶x)=[x]go(向左向右分支)=向左+向右快速展平::树a->[a]flature Fast=DList.toList。去哪里go(叶x)=DList.singleton xgo(Branch left right)=向左移动`DList.append`向右移动
(上述代码可在基准.)
展平速度慢
可能比快速展平
:
-
展平速度慢
使用++
串联列表,每个列表都是递归的由左边
和正确的
树
中的值分行
构造函数。
-
快速展平
不使用++
而是构建一个功能组合,每一个都是由DList.singleton列表
((x:)
). 这个功能D列表到列表
将组合函数应用于[]
,正在构造最后是一个列表。
要了解两者之间的差异展平速度慢
和快速展平
,考虑一些应用于树
:
平展缓慢(分支(分支(叶'a')(叶'b'))(叶'c'))=go(分支(分支(叶'a')(叶'b'))(叶'c'))=go(分支(叶'a')(叶'b'))++go(叶'c')=(go(叶子'a')++go(树叶'b'))++“c”=(“a”++“b”)++“c”=('a':[]++“b”)++“c”=('a':“b”)++“c”=“a”:“b”++“c”=“a”:“b”:[]++“c”=“a”:“b”:“c”
flawnFast(分支(分支(叶“a”)(叶“b”))(叶“c”))=toList$go(分支(分支(叶'a')(叶'b'))(叶'c'))=toList$go(分支(叶'a')(叶'b'))`append`go(叶'c')=unsafeApplyDList(go(分支(叶'a')(叶'b')))。unsafeApplyDList(go(叶'c'))$[]=unsafeApplyDList(go(分支(叶'a')(叶'b')))=unsafeApplyDList(go(分支(叶'a')(叶'b')))=unsafeApplyDList(go(分支(叶'a')(叶'b')))=unsafeApplyDList(go(分支(叶'a')(叶'b')))“c”=unsafeApplyDList(不安全列表(unsafeAppleDList)(go(叶'a'))。unsafeApplyDList(go(叶'b')))“c”=unsafeApplyDList(go(叶'a'))=unsafeApplyDList(go(叶'a'))=unsafeApplyDList(go(叶'a'))=unsafeApplyDList(go(叶'a'))('b':“c”)=unsafeApplyDList(单例'a')('b':“c”)=不安全应用DList(不安全列表((:)'a'))('b':“c”)=“a”:“b”:“c”
左翼阵营++
在里面展平速度慢
中间列表构造的结果在评估最外层时立即丢弃的++
。在另一方面,对快速展平
不涉及中间列表结构,而非功能应用和新型
构造函数包装和展开包装。这就是效率的来源。
警告!请注意,上面有一些事实,但也有很多省力和内在复杂性。例如,可能存在GHC重写适用于的规则++
,这将改变实际评估。和,共当然,严格、懒惰和分享都起着重要作用。同样,不是中的每个函数数据清单
套餐对于任何情况都是最有效的。
故事的寓意:如果您正在使用数据清单
要加快代码速度,请检查确保它确实如此。基准!
设计说明
以下是针对数据清单
包裹。
避免++
休斯将列表表示为一级功能的初衷是提供一个抽象,以便列表追加
在中找到操作函数式编程语言(现在称为++
Haskell)不会出现在左列的位置以避免与列表相同的重复结构构建。多年来,许多使用list的人吸取的教训是这个追加
有时令人惊讶的是,操作可能会出现在他们不知道的地方期待吧。
我们的目标之一是数据清单
软件包以避免让用户惊讶意外插入++
。为此,应该有一个最小集的函数数据清单
在哪儿++
可以直接或间接找到。这个已知用途列表++
包括:
D列表
:来自列表
,来自字符串
,阅读
DN非空
:从列表
,来自非空
,来自字符串
,阅读
如果任何未来请求的功能涉及++
(例如,通过来自列表
),负担包容性高于其他情况。
抽象
这个D列表
表示及其支持功能(例如。追加
,势利小人
,等)依赖不变量来保持其安全使用。就是说,没有这个不变量,用户可能会遇到意外的结果。
(我们使用的安全性是指语义定义明确且符合预期,不是指参照透明的一面。不变量不直接导致副作用数据清单
包,但程序使用不安全生成D列表
可能会做出令人惊讶的事情。)
不变量是,对于任何xs::D列出
:
fromList(toList xs)=xs
要查看如何打破此不变量,请考虑以下示例:
xs::D列出xs=不安全列表(const[])fromList(toList(xs`snoc`1))=fromList(toList(不安全列表(const[])`snoc`1)=fromList(toList(不安全列表(不安全应用DList(不安列表(const[])))。(x:))=fromList(toList(不安全列表(常量[].(x:)))=fromList(($[])。unsafeApplyDList$UnsafeDList(常量[].(x:))=来自列表(常量[].(x:)$[])=fromList(常量[][x])=来自列表[]=不安全列表(++[])
不变量也可以表示为:
toList(fromList(toList xs))=toList x
我们可以将示例重申为:
toList(fromList(toList(xs`snoc`1))=toList(不安全列表(++[]))= []
如果发现这一点,那将是非常无益和令人惊讶的(xs`snoc`1)
结果是成为空列表。
保持上的不变量D列表
,我们在数据。D列表
模块。建造师,不安全列表
和记录标签,不安全应用DList
,不会导出,因为可以使用这些,如上所示,打破不变量。
尽管如此,仍有许多人要求出口D列表
构造函数。我们不相信这是必要的,但我们相信用户应该自己决定。
使用的构造函数和记录标签D列表
,您可以按如下方式导入它们:
导入数据。D列表。不安全(DList(不安全DList,不安全应用DList))
如果你正在使用Safe Haskell,你可能需要在你的模块:
{-#LANGUAGE值得信赖#-}
请注意,安全证明的责任在于你。
工具书类
这些是各种参考资料,您可以从中了解更多关于差异列表的信息。
研究
背景
博客和邮件列表
书
许可证
BSD 3条款“新”或“修订”许可©Don Stewart,Sean Leather,版权所有,贡献者