Haskell -从无限列表中获取多个值,而无需重新开始列表



我目前正在研究欧拉项目40问题的实现,并试图找出如何在Haskell中从列表中取出多个项目而无需重新开始列表。

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

ans = (product . map (champernowne !!)) [0, 9, 99, 999, 9999, 99999]

这个实现的问题是(我假设)Haskell每次想要获得一个新项时都会从序列的开始遍历列表。我怎样才能让haskell只遍历从元素1到1 000 000的序列然后把中间的项取出来呢?我已经尝试了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]

最新更新