List Haskell列表复杂性

List Haskell列表复杂性,list,haskell,concatenation,List,Haskell,Concatenation,抱歉,如果已经问过这个问题,我没有找到它。对不起,我的英语很差 我正在学习Haskell并尝试使用列表。 我写了一个函数,它按照特定的模式转换列表,我现在无法检查它是否有效,但我想是的 此函数不是尾部调用函数,因此我认为用一个大列表计算此函数会很糟糕: transform :: [Int] -> [Int] transform list = case list of (1:0:1:[]) -> [1,1,1,1] (1:1:[]) -> [1,0,1] [1

抱歉,如果已经问过这个问题,我没有找到它。对不起,我的英语很差

我正在学习Haskell并尝试使用列表。 我写了一个函数,它按照特定的模式转换列表,我现在无法检查它是否有效,但我想是的

此函数不是尾部调用函数,因此我认为用一个大列表计算此函数会很糟糕:

transform :: [Int] -> [Int]
transform list = case list of
  (1:0:1:[])  -> [1,1,1,1]
  (1:1:[])    -> [1,0,1]
  [1]         -> [1,1]
  (1:0:1:0:s) -> 1:1:1:1: (transform s)
  (1:1:0:s)   -> 1:0:1: (transform s)
  (1:0:s)     -> 1:1: (transform s)
  (0:s)       -> 0: (transform s)
所以我想到了另一个功能,它会“更好”:

问题是我不知道它是如何编译的,也不知道第二个函数是否错了。你能解释一下列表是如何工作的吗?在最后使用(++)还是颠倒列表更好


提前感谢您的回答

第一个功能非常好,我认为比第二个更好

原因是懒惰。如果代码中有一个
transform-someList
表达式,则除非您要求,否则不会计算结果列表。特别是,仅在需要时对清单进行评估
print$take 10$transform xs
print$take 20$transform xs
所做的工作要少

在严格的语言中,
transform
确实会妨碍堆栈,因为它必须在返回任何有用的内容之前(以非尾部递归方式)计算整个列表。在Haskell
transform(0:xs)
中,计算结果为
0:transform xs
,这是一个可用的部分结果。我们可以在不接触尾部的情况下检查结果的头部。也没有堆栈溢出的危险:在任何时候,列表末尾最多有一个未计算的thunk(如上例中的
transformxs
)。如果您需要更多元素,thunk将被进一步向后推,并且可以对前一个thunk的堆栈帧进行垃圾收集


如果我们总是完全评估列表,那么这两个函数的性能应该是相似的,甚至因为缺少反转或额外的
++
-s,延迟版本可能会更快一些。因此,通过切换到第二个函数,我们失去了惰性,也没有获得额外的性能。

在我看来,您的第一个版本要好得多。它不是尾部递归的,这很好:你不希望它是尾部递归的,你希望它是懒惰的。如果不处理整个输入列表,第二个版本甚至不能生成单个元素,因为为了
反转
aux
的结果,必须知道
aux
的全部内容。但是,

take 10 . transform $ cycle [1,0,0,1,1,1]
对于您的第一个定义
transform
,可以很好地使用,因为您只需要根据需要使用列表中的内容来做出决策


1但是请注意,
(1:0:1:[])
只是
[1,0,1]

非常感谢你的回答,我明白我现在在做什么,所以我不得不更多地依靠懒惰。我太习惯于严格的语言了。谢谢,我想,用模式匹配来匹配[1,0,1]是行不通的。。。但它只是一个值,所以它当然会起作用。
take 10 . transform $ cycle [1,0,0,1,1,1]