简体   繁体   English

在Unboxed Vectors上记忆函数会导致它挂起

[英]Memoising a function over Unboxed Vectors causes it to hang

I'm playing with Vectors and Unboxed Vectors, with a fairly simple program. 我正在玩Vector和Unboxed Vectors,程序相当简单。 I'm enumerating all integers whose only factors are 2,3 & 5. 我列举了所有只有2,3和5因子的整数。

I thought I'd try memoising it over Data.Vector which worked and was super easy. 我以为我会尝试通过Data.Vector ,这样做起来非常简单。 So I thought I'd try Data.Vector.Unboxed . 所以我想我会尝试Data.Vector.Unboxed However, it hangs when z is [0..5] , but not when z is [0..4] and I'm not sure why. 但是,当z为[0..5]时它会挂起,但是当z为[0..4]时它不会挂起,我不知道为什么。 The difference between the two is that 5 involves a mutually recursive call. 两者之间的区别在于5涉及相互递归的调用。

What's going wrong here? 这里出了什么问题?

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

All unboxed containers are deep-strict, which means you can't use them for lazy memoisation: before any element is accessible as memoised, you have to have all of them evaluated. 所有未装箱的容器都是深度严格的,这意味着你不能将它们用于懒惰的记忆:在任何元素可以被记忆后访问之前,你必须对所有元素进行评估。

As to why this is so: when you have a normal lazy thunk in Haskell, it's the box that carries this information about that the value is not yet in NF right now, but to make it so you can execute this piece of code . 至于为什么会这样:当你在Haskell中有一个正常的懒惰时,它就是带有关于该值现在还没有在NF中的信息的盒子 ,但为了使它能够执行这段代码 After that's been done the box is basically just a pointer to the result. 完成之后,框基本上只是指向结果的指针。
That's a great help in many situations, but it's not for free memory- or performance-wise: that's precisely the overhead which unboxed containers remove, by directly storing the result information in a tight array. 在许多情况下,这是一个很好的帮助,但它不是免费的内存或性能:通过直接将结果信息直接存储在紧密的数组中,这正是未装箱容器移除的开销。

In this specific case (all recursive calls are to smaller indices, and n can be reconstructed from the already-computed vector), you can use constructN (it works iteratively rather than relying on laziness): 在这种特定情况下(所有递归调用都是较小的索引,并且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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM