List 哈斯克尔&x2014;从无限列表中获取多个值,而无需重新启动列表

List 哈斯克尔&x2014;从无限列表中获取多个值,而无需重新启动列表,list,haskell,lazy-evaluation,List,Haskell,Lazy Evaluation,我目前正致力于的一个实现,并试图找出如何从Haskell中的列表中获取多个项目,而无需重新开始列表 目前,我有一个champernowne类型的列表Integral a=>[a],它将返回champernowne常数的无限位数列表,然后我从这个序列中取第一个、第十个等项,并将它们相乘得到答案。实际代码为: ans = (product . map (champernowne !!)) [0, 9, 99, 999, 9999, 99999] 这个实现的问题是(我假设)每次Haskell想要得到

我目前正致力于的一个实现,并试图找出如何从Haskell中的列表中获取多个项目,而无需重新开始列表

目前,我有一个
champernowne
类型的列表
Integral a=>[a]
,它将返回champernowne常数的无限位数列表,然后我从这个序列中取第一个、第十个等项,并将它们相乘得到答案。实际代码为:

ans = (product . map (champernowne !!)) [0, 9, 99, 999, 9999, 99999]
这个实现的问题是(我假设)每次Haskell想要得到一个新的术语时,它都会从序列的开头遍历列表。我怎样才能使haskell只遍历从元素1到1000000的序列,然后从中间抽出术语?我已经尝试过scanl,希望惰性评估能帮助我,但它没有:

ans = (product . head . scanl (flip drop) champernowne) [10, 90, 900, 9000, 90000]

澄清一下,第一段代码确实有效,但我正在努力改进我的实现,使其更高效。

解决这个问题的有效方法是计算数字而不构建列表

但是,如果您所需的索引是按升序给出的,那么您可以通过计算相对偏移量和
drop
ping适当数量的项目来达到下一个所需的索引,而无需从头开始

-- supposes the list of indices in ascending order
indices :: [a] -> [Int] -> [a]
indices xs is = go xs offsets
  where
    offsets = zipWith (-) is (0:is)
    go ys (k:ks) = case drop k ys of
                     z:zs -> z : go (z:zs) ks
                     _    -> []
    go _ [] = []

第二个表达式中有一个小错误:使用
map head
而不是
head

map (list !!) xs   -- [0, 9, 99, 999, 9999, 99999] ==

map head . tail . scanl (flip drop) list $ zipWith (-) xs (0:xs)
                   -- [9, 90, 900, 9000, 90000]

snd$unzip$filter(\(i,\)->i`elem`[10,909009009000])$zip[1..10000000]champernowne@EarlGray你能解释一下那一行吗?尽管得到了正确的答案,但它的运行速度似乎比原来的慢了很多。
zip
生成了一个懒散的配对列表[(1,champ!!0),(2,champ!!1),…,(10000000,champ!!99999)]。然后,该列表通过过滤器进行过滤:是列表中元组1的第一项
[10、90、900、9000,随便什么]
。过滤结果通过解压运行,解压将返回
([],[])
。然后,
snd
只接受
[]
。在我的oneliner中,列表
champernowne
只生成一次,因此如果您的解决方案速度更快,您不必担心它的性能。谢谢!我将研究我是如何构造我的列表实现的,看看是否可以使它更高效。它不应该是“drop(k-1)ys”,第一个偏移量有一个特例(可能是压缩“-1:is”)?@ItaiZukerman不在这里,我允许重复索引,因此将所选元素放回从中删除的列表中。如果所选元素没有放回,则可能是
drop(k-1)
,这可能是更常见的情况。