我正在玩Vector和Unboxed Vectors,程序相当简单.我列举了所有只有2,3和5因子的整数.
我以为我会尝试记忆Data.Vector
哪个有效并且非常简单.所以我想我会试试Data.Vector.Unboxed
.但是,当z是,它会挂起[0..5]
,但是当z是[0..4]
,我不知道为什么.两者之间的区别在于5
涉及相互递归的调用.
这里出了什么问题?
import Data.Vector.Unboxed as UV memoisingCandidateUV :: UV.Vector Bool memoisingCandidateUV = UV.map isCandidateUV z isCandidateUV :: Int -> Bool isCandidateUV 0 = False isCandidateUV n | n2r == 0 = n2q == 1 || memoisingCandidateUV UV.! n2q | n3r == 0 = n3q == 1 || memoisingCandidateUV UV.! n3q | n5r == 0 = n5q == 1 || memoisingCandidateUV UV.! n5q | otherwise = False where (n2q, n2r) = n `quotRem` 2 (n3q, n3r) = n `quotRem` 3 (n5q, n5r) = n `quotRem` 5
leftaroundab.. 8
所有未装箱的容器都是深度严格的,这意味着你不能将它们用于懒惰的记忆:在任何元素可以被记忆后访问之前,你必须对所有元素进行评估.
至于为什么会这样:当你在Haskell中有一个正常的懒惰时,它就是带有关于该值现在还没有在NF中的信息的盒子,但为了使它能够执行这段代码.完成之后,框基本上只是指向结果的指针.
在许多情况下,这是一个很好的帮助,但它不是为了免费的内存或性能:通过直接将结果信息直接存储在紧密的数组中,这正是未装箱容器移除的开销.
所有未装箱的容器都是深度严格的,这意味着你不能将它们用于懒惰的记忆:在任何元素可以被记忆后访问之前,你必须对所有元素进行评估.
至于为什么会这样:当你在Haskell中有一个正常的懒惰时,它就是带有关于该值现在还没有在NF中的信息的盒子,但为了使它能够执行这段代码.完成之后,框基本上只是指向结果的指针.
在许多情况下,这是一个很好的帮助,但它不是为了免费的内存或性能:通过直接将结果信息直接存储在紧密的数组中,这正是未装箱容器移除的开销.
在这种特定情况下(所有递归调用都是较小的索引,并且n
可以从已经计算的向量重建),您可以使用constructN(它迭代地工作而不是依赖于懒惰):
import Data.Vector.Unboxed as UV memoisingCandidateUV :: UV.Vector Bool memoisingCandidateUV = UV.constructN 100 isCandidateUV isCandidateUV :: UV.Vector Bool -> Bool isCandidateUV vec = result where n = UV.length vec result | n == 0 = False | n2r == 0 = n2q == 1 || vec UV.! n2q | n3r == 0 = n3q == 1 || vec UV.! n3q | n5r == 0 = n5q == 1 || vec UV.! n5q | otherwise = False (n2q, n2r) = n `quotRem` 2 (n3q, n3r) = n `quotRem` 3 (n5q, n5r) = n `quotRem` 5