简体   繁体   English

哈斯克尔的“尾巴”函数有什么时间复杂性?

[英]What Time Complexity Does Haskell's “tail”-Function Have?

I was reading a tutorial on Haskell when I thought to myself; 当我想到自己时,我正在阅读关于Haskell的教程; what time complexity does Haskell's tail function have (and why)? Haskell的tail函数具有什么时间复杂度(以及为什么)? (I cannot find an answer in any documentation) (我在任何文档中都找不到答案)

I would guess that for a list of size n, the tail function would be O(n) , ie just copying over the tail to a new list and returning that one. 我猜想对于大小为n的列表, tail函数将是O(n) ,即只是将尾部复制到新列表并返回该列表。 But then again, I do not know too much about the underlying architecture of Haskell (I'm new to the language). 但话说回来,我不太了解Haskell的底层架构(我是语言的新手)。

Of course, I could time it. 当然,我可以计时。 But I don't know how to time stuff in Haskell yet, and I also want to learn how Haskell handles the problem, to justify why it is O(n)/O(1) or whatever. 但我还不知道如何在Haskell中计算时间,我也想了解Haskell如何处理问题,证明为什么它是O(n)/ O(1)或其他什么。

Thanks in advance :) 提前致谢 :)

Haskell the language doesn't specify. Haskell语言没有指定。 But in GHC (the most frequently used implementation), it is O(1). 但在GHC(最常用的实现)中,它是O(1)。 The tail does not need to be copied -- it is safe to share between the original list and whoever uses just the tail of the list -- because everything in Haskell is immutable. 尾部不需要复制 - 在原始列表和只使用列表尾部的人之间共享是安全的 - 因为Haskell中的所有内容都是不可变的。

Challenge problem: why does init , which keeps all but the last element of a list, run in O(n)? 挑战问题:为什么除了列表的最后一个元素之外的所有init都在O(n)中运行? Why doesn't the sharing argument above apply there? 为什么上面的共享参数不适用于那里?

Short answer: if the list is already constructed up to that node, O(1) . 简短回答:如果列表已构建到该节点,则为O(1)

A list in Haskell is a linked list . Haskell中的列表是一个链表 It is defined as: 它被定义为:

data [a] = [] | a : [a]

So that means that either we have the empty list, or the a : [a] construct. 这意味着要么我们有空列表,要么是a : [a]构造。 So a node with a head (the a ) that refers to an object of type a , and a tail that refers to a list [a] (which can be the empty list, or another node). 因此,具有heada )的节点引用类型a的对象, tail引用列表[a] (可以是空列表或另一个节点)。

The source code of the tail in base is defined as: base tail的源代码定义为:

 tail :: [a] -> [a] tail (_:xs) = xs tail [] = errorEmptyList "tail" 

It runs in O(1) since we simply follow the pointer to the "tail" of that node. 它在O(1)中运行,因为我们只需按指向该节点的“尾部”。

Mind however that Haskell works lazily . 但请注意Haskell懒惰地工作 It is not because we get an object of type [a] that we have a materialized list: usually Haskell will first have to evaluate the expression tree it has been given up to the given node. 这不是因为我们得到一个类型为[a]的对象,我们有一个物化列表:通常Haskell首先必须评估它已经放弃给定节点的表达式树 This can result in evaluating a complex and time consuming algorithm. 这可能导致评估复杂且耗时的算法。 So it depends on the expression tree you have been given . 所以它取决于你给出的表达式树

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM