【问题标题】:How does haskell create a new list from another list?haskell 如何从另一个列表创建一个新列表?
【发布时间】:2016-08-18 11:02:12
【问题描述】:

假设我们有一个列表

x = [1..10]

我们打算以这种方式创建另一个列表 y:

y= [a|a<-x]

因此,在从x 创建列表y 时,它会访问x(从1 到10)的每个元素,并以相同的顺序将其插入y。由于 haskell 中的列表是单链表,我们只能在其头部插入一个新元素。所以首先它将 1 插入到[] 并且我们有[1]。然后它将 2 插入到它的头部 & 所以我们有[2,1]。然后它插入 3 & 我们有 [3,2,1] 等等。所以最终我们应该得到y 作为[10,9..1]。但相反,我们得到y[1..10]。为什么会这样?

【问题讨论】:

标签: list haskell list-comprehension lazy-evaluation


【解决方案1】:

因为它将它们“插入”到列表的尾部(在构建列表时),而不是头部(参见“尾部递归模数”):

[a | a <- [1..10]]     ==
[a | a <- (1:[2..10])] ==      -- [a | a <- ([1] ++ [2..10])]
1 : [a | a <- [2..10]]         -- [1] ++ [a | a <- [2..10]]

这是因为

[a | a <- (xs ++ ys)]  ==  [a | a <- xs] ++ [a | a <- ys]

[a | a <- ys]  ==  ys

【讨论】:

    【解决方案2】:

    您对列表推导的思考方式并不完全正确。当你看到理解时

    y <- [f a | a <- x]
    

    您不应该考虑将连续结果添加到(最初为空)结果列表的前面。

    相反,请考虑将每个f a 添加到对x 的其余部分运行列表推导的结果的前面。也就是说,

    [f a | a <- x:xs] == f x : [f a | a <- xs]
    

    这是一种递归方法 - 通过假设结果列表存在于列表的尾部,您可以将下一个结果添加到它的前面。

    【讨论】:

      【解决方案3】:

      看看列表推导式是如何去糖化单子计算的,而不是使用直觉来了解它们是如何工作的,这很有启发意义。

      [a | a <- [1..3]] == do {a <- [1..3]; return a}   -- desugared comprehension
                        == [1..3] >>= return a          -- desugared do
                        == concat (map return [1..3])   -- definition of >>=
                        == concat [[1], [2], [3]]       -- defintiion of return
                        == [1,2,3]                      -- definition of concat
      

      【讨论】:

        猜你喜欢
        • 2018-01-31
        • 2018-10-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多