【问题标题】:Can the head of a list ever represent more than one value列表的头部可以代表多个值吗
【发布时间】:2016-10-16 08:40:02
【问题描述】:

如果我像这样调用函数interleave(定义如下 - 它是一个在列表的每个位置插入一个数字(或任何类型)的函数),结果列表的长度都是相同的

interleave 1 [2,3,4]
[[1,2,3,4],[2,1,3,4],[2,3,1,4],[2,3,4,1]]

但是,我预计列表长度会越来越短,因为对interleave 的递归调用会通过列表减去头部(即只有ys)。由于每次调用后列表的尾部都会越来越短,因此我希望生成的列表会更短。

interleave :: a -> [a] -> [[a]]
interleave x []     = [[x]]
interleave x (y:ys) = (x:y:ys) : map (y:) (interleave x ys)

如果递归调用的列表参数越来越短,列表如何最终保持相同的长度?

我能想象的唯一答案是映射值 map (y:) 在递归调用中表示不止一位(即它是 [2,1,3,4] 中的 2 和 [2, 3,1,4] 和 [2,3,4,1] 中的2,3,4,但我不确定这是否可能,我不知道如何在 haskell 中执行期间记录值。

问题,换句话说,y(列表的头部)能否在递归调用中表示多个值?

在回答问题时(如果相关),请确认/解释(x:y:ys) : map (y:) (interleave x ys) 中的(x:y:ys) 是否仅代表一个列表(即它是插入整数参数的 [1,2,3,4-在第一位置)。

(如果您可以显示函数的执行顺序,或者值如何存储在堆栈中,这可能会有所帮助)

【问题讨论】:

  • 注意,我很难确定要问的正确问题。如果问题应该以不同的方式提出,请告诉我。
  • 看到了很多不好的问题,让我向你保证:你做得很好。

标签: haskell recursion


【解决方案1】:

递归调用的列表长度确实越来越短;但是,该函数会修改递归调用的结果以延长它们。让我们从底部开始。对于空列表,不会发生任何有趣的事情:

interleave 1 []
= { first clause of definition }
[[1]]

但是当我们得到一个包含一个元素的列表时,我们已经看到了有趣的事情正在发生。具体来说,由于递归调用的结果被传递给map (y:),因此递归调用生成的短列表每个都扩展了一个元素。

interleave 1 [4]
= { list syntax }
interleave 1 (4:[])
= { second clause of definition }
(1:4:[]) : map (4:) (interleave 1 [])
= { recursive call, which produces short answers }
(1:4:[]) : map (4:) [[1]]
= { definition of map, which lengthens each answer }
(1:4:[]) : [4:[1]]
= { list syntax }
[[1,4],[4,1]]

以类似的方式,interleave 1 [3,4] 进行递归调用 interleave 1 [4] 以生成 [[1,4],[4,1]],然后使用 map (3:) 将其中的每个元素延长为 [[3,1,4],[3,4,1]]

现在依次解决您的直接问题:

如果递归调用的列表参数越来越短,列表如何最终保持相同的长度?

每次对较短的列表进行递归调用时,递归调用的结果都会变长——这些结果完全平衡,因此使用长度为n 的列表调用interleave 将产生一个集合长度-n+1 列表。

y(列表头)能否在递归调用中表示多个值?

不,列表的头部始终是单个值。真正的魔力在于,每个递归调用都会添加到头部——因此您可以从许多递归调用中获得许多额外的头部。

确认/解释(x:y:ys) : map (y:) (interleave x ys) 中的(x:y:ys) 是否只代表一个列表(即它是[1,2,3,4-,在第一个位置插入了整数参数)。

正确。

【讨论】:

  • 这仍然让我感到困惑:Each time a recursive call on a shorter list is made, the results of the recursive call are made longer -- these are exactly balanced out so that calling interleave with a length-n list will result in a collection of length-n+1 lists. 例如,如果(在来自操作的示例中)尾部 ys 只是 [4](因为它将在末尾),并且只有一个值映射到列表(y:),我仍然不明白最终列表如何可以是四个值。递归调用的逐渐变长的结果是否由 func 中的值表示?
  • @Leahcim 调用interleave 1 [2,3,4](调用此A)调用interleave 1 [3,4](B),调用interleave 1 [4](C),调用interleave 1 [](D)。 D 返回长度为 1 的列表;然后 C 在返回之前为每个列表添加一个元素,因此 C 返回长度为 2 的列表。然后 B 在 C 生成的每个列表中添加一个元素,因此 B 返回长度为 3 的列表。然后 A 为每个列表添加一个元素由 B 生成的列表,因此 A 返回长度为 4 的列表。换句话说:不是只有一个值被前置的情况,尽管 每个调用只前置一个(更多)价值。
  • 谢谢你,这个评论很有帮助,我已经接受了你的回答。仍然不清楚的一件事(您或其他人是否有时间回答)是 D 作为最终调用,如何返回“列表”(即为什么它返回多个列表?)。根据我从您的回答中了解到的情况,每次调用返回的列表数量将等于对 interleave 的调用次数(每个列表的长度会发生变化)但是如何从 interleave 1 [] 返回四个长度为 1 的列表?再次感谢您的帮助
  • @Leahcim 实际上,列表本身和列表列表在每次递归调用中都扩展了一个。在(x:y:ys) : map (y:) (...) 中,map 扩展了递归调用返回的每个列表,然后(x:y:ys) : ... 将一个附加列表添加到列表列表中。所以interleave 1 [] 返回一个列表列表,其中只有一个列表,其余调用添加到剩余列表中。
猜你喜欢
  • 1970-01-01
  • 2012-04-03
  • 2012-12-17
  • 2011-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多