问题描述
如果我这样创建一个无限列表:
let t xs = xs ++ [sum(xs)]
let xs = [1,2] : map (t) xs
take 10 xs
我会得到以下结果:
[
[1,2],[1,2,3],3,6],6,12],12,24],24,48],48,96],96,192],192,384],384,768]
]
这与我要执行的操作非常接近。
此当前代码使用最后一个值定义下一个。但是,除了列表列表以外,我想知道一种制作无限列表的方法,该列表使用所有先前的值定义新列表。
所以输出将只是
[1,768,1536,...]
我已经定义了第一个元素[1]
。
我有一个获取新元素的规则,将所有先前的元素加总。 但是,我无法将其放入Haskell语法中以创建无限列表。
使用当前代码,我可以使用以下命令获取所需列表:
xs !! 10
> [1,1536]
但是,在我看来,有可能以更有效的方式做到这一点。
一些注释
我知道,对于这个特定示例,这是故意过分简化的,我们可以创建一个仅使用最后一个值来定义下一个的函数。
但是,我正在搜索是否有可能将所有先前的值读入一个无限列表定义中。
很抱歉,如果我使用的示例引起了一些混乱。
再举一个例子,仅读取最后一个值是不可能解决的:
isMultipleByList :: Integer -> [Integer] -> Bool
isMultipleByList _ [] = False
isMultipleByList v (x:xs) = if (mod v x == 0)
then True
else (isMultipleByList v xs)
nextNotMultipleLoop :: Integer -> Integer -> [Integer] -> Integer
nextNotMultipleLoop step v xs = if not (isMultipleByList v xs)
then v
else nextNotMultipleLoop step (v + step) xs
nextNotMultiple :: [Integer] -> Integer
nextNotMultiple xs = if xs == [2]
then nextNotMultipleLoop 1 (maximum xs) xs
else nextNotMultipleLoop 2 (maximum xs) xs
addNextNotMultiple xs = xs ++ [nextNotMultiple xs]
infinitePrimeList = [2] : map (addNextNotMultiple) infinitePrimeList
take 10 infinitePrimeList
[
[2,[2,5],5,7],7,11],11,13],13,17],17,19],19,23],23,29],29,31]
]
infinitePrimeList !! 10
[2,31,37]
解决方法
您可以这样认为:
- 您要创建一个以
a
开头的列表(称为[1,2]
):
a = [1,2] ++ ???
- ...并具有此属性:
a
中的每个下一个元素都是a
中所有先前元素的总和。这样你就可以写
scanl1 (+) a
并获得一个新列表,其中索引为n
的任何元素都是列表n
的{{1}}个头元素的总和。因此,它是a
。您需要做的就是不带任何先机地获取所有元素:
[1,3,6 ...]
因此,您可以将tail (scanl1 (+) a)
定义为:
a
这种想法可以通过其元素应用于定义列表的其他类似问题。
,如果我们已经有了最终结果,则可以很容易地计算出给定元素的先前元素列表,这是inits函数的简单应用。
假设我们已经已经最终结果xs
,并使用它来计算xs
本身:
import Data.List (inits)
main :: IO ()
main = do
let is = drop 2 $ inits xs
xs = 1 : 2 : map sum is
print $ take 10 xs
这将产生列表
[1,2,6,12,24,48,96,192,384]
(注意:这比SergeyKuz1001的解决方案效率低,因为每次都会重新计算总和。)
, unfoldr
具有很好的灵活性,可以适应各种“从初始条件创建列表”问题,因此我认为值得一提。
在这种情况下,优雅程度有所降低,但展示了如何使用unfoldr
。
import Data.List
nextVal as = Just (s,as++[s])
where s = sum as
initList = [1,2]
myList =initList ++ ( unfoldr nextVal initList)
main = putStrLn . show . (take 12) $ myList
屈服
[1,384,768,1536]
最后。
正如评论中指出的那样,使用unfoldr时应该三思。我在上面的编写方式中,该代码模仿了原始问题中的代码。但是,这意味着用as++[s]
更新累加器,从而在每次迭代时构造一个新列表。在https://repl.it/languages/haskell处快速运行表明它变得非常占用内存且速度很慢。 (4.5秒访问myList
中的第2000个元素
将交换器更新仅交换为a:as
,速度提高了7倍。由于相同的列表可以在每个步骤中作为累加器重用,因此运行速度更快。但是,累加器列表现在是相反的,因此需要三思。对于谓词功能sum
,这没有什么区别,但是如果列表的顺序很重要,则必须多加考虑。
您可以这样定义它:
xs = 1:2:iterate (*2) 3
例如:
Prelude> take 12 xs
[1,1536]
,
这是我的看法。我尝试不创建O(n)个额外列表。
explode ∷ Integral i ⇒ (i ->[a] -> a) -> [a] -> [a]
explode fn init = as where
as = init ++ [fn i as | i <- [l,l+1..]]
l = genericLength init
此便利功能确实会创建其他列表(按take
)。希望它们可以被编译器优化。
explode' f = explode (\x as -> f $ take x as)
用法示例:
myList = explode' sum [1,2]
sum' 0 xs = 0
sum' n (x:xs) = x + sum' (n-1) xs
myList2 = explode sum' [1,2]
在我的测试中,这两个功能之间几乎没有性能差异。 explode'
通常会稍微好一些。
solution中的@LudvigH非常清晰。但是,速度并不快。
我仍在研究基准测试以比较其他选项。
目前,这是我能找到的最佳解决方案:
-------------------------------------------------------------------------------------
-- # infinite sum of the previous using fuse
-------------------------------------------------------------------------------------
recursiveSum xs = [nextValue] ++ (recursiveSum (nextList)) where
nextValue = sum(xs)
nextList = xs ++ [nextValue]
initialSumValues = [1]
infiniteSumFuse = initialSumValues ++ recursiveSum initialSumValues
-------------------------------------------------------------------------------------
-- # infinite prime list using fuse
-------------------------------------------------------------------------------------
-- calculate the current value based in the current list
-- call the same function with the new combined value
recursivePrimeList xs = [nextValue] ++ (recursivePrimeList (nextList)) where
nextValue = nextNonMultiple(xs)
nextList = xs ++ [nextValue]
initialPrimes = [2]
infiniteFusePrimeList = initialPrimes ++ recursivePrimeList initialPrimes
这种方法速度很快,并充分利用了许多内核。
也许有一些更快的解决方案,但我决定发布此信息,以分享到目前为止我在该主题上的最新进展。
,通常,定义
EndRead
然后是xs = x1 : zipWith f xs (inits xs)
,依此类推。
Here's在计算素数的无限列表(将它们配对为
)的背景下使用xs == x1 : f x1 [] : f x2 [x1] : f x3 [x1,x2] : ....
的一个示例
inits
(在ps = 2 : f p1 [p1] : f p2 [p1,p2] : f p3 [p1,p2,p3] : ...
的定义中)。