【问题标题】:Generate infinite list from function results从函数结果生成无限列表
【发布时间】:2016-12-18 06:37:14
【问题描述】:

我有一个函数,它接受一个整数并返回一个整数列表。

我如何有效地将这个函数映射到一个初始整数,然后对于结果列表中之前未映射的每个项目,应用相同的函数并基本上生成一个无限列表。

例如

f :: Int -> [Int]
f 0 = [1,2]++(f 1)++(f 2)

此外,我需要能够将结果列表索引到 10E10。这将如何优化?记忆?

【问题讨论】:

  • 这可能是一个没有经过深思熟虑的例子,但这个定义是无效的。 f为 0 定义; f 1f 2 根本没有定义。您可能想了解Data.List.unfoldr
  • @chepner 我可以添加更多示例,但我不想定义超出理解问题所必需的内容

标签: algorithm haskell memoization


【解决方案1】:

您需要广度优先搜索。基本的成语是这样的:

bfs :: (a -> [a]) -> [a] -> [a]
bfs f xs = xs ++ bfs f (concatMap f xs)

请注意我们如何在参数xs 中保留当前“状态”,将其输出,然后递归调用一个新状态,即f 应用于输入状态的每个元素。

如果你想过滤掉你以前没见过的元素,你还需要传递一些额外的状态来跟踪你见过的元素,例如Data.Set,并相应地调整算法。我会把这点留给你,因为我是一个令人讨厌的教育家。

【讨论】:

  • 谢谢,这和我想出的很相似,没想到是bfs。但是有没有可能的优化?目前在我的机器上获取结果列表的 10E6 值大约需要 20 秒。
  • 如果有任何重复的值,修剪它们将有很大帮助,如果你还没有这样做的话。广度优先搜索也应该很好地并行化,但是正确调整可能很棘手(而且我并不是这方面的专家——可能是另一个 SO 问题的素材)。否则,我会在您正在搜索的函数中寻找一些可以利用的数学结构(例如,如果它总是计算两个值,您可以使用一些对数或其他东西计算第 10e6 个元素的精确表达式)。
  • 哦,一个随机的想法,你可以尝试严格索引 ix 0 (x:xs) = x; ix n (x:xs) = x `seq` ix (n-1) xs 来获取第 n 个元素。如果函数非常简单,您可能会遇到一些 thunk 堆积。当然,像往常一样使用-O 编译您的代码。
猜你喜欢
  • 2013-05-28
  • 2023-03-22
  • 2014-01-21
  • 1970-01-01
  • 1970-01-01
  • 2015-12-27
  • 1970-01-01
  • 2012-06-27
  • 1970-01-01
相关资源
最近更新 更多