如何在Haskell中存储和访问预先计算的数组数据?

ercv8c1e  于 11个月前  发布在  其他
关注(0)|答案(1)|浏览(84)

我在做一个Haskell库。我需要一个大的(约10万个项目)带整数值的未装箱数组,以便不时地从库的各个部分访问它们。数组应该包含需要初始化一次的预先计算的数据。它们的初始化的实现没有问题。问题是如何更好地构造它们的初始化,并为其余部分提供对它们的访问。图书馆。我考虑以下可能性:
1.用数组定义一个记录类型,并使用Readermonad提供一个预计算数据的环境。
1.使用ST monad构建数组,并使用每个数组的常规函数访问它们。
第一个选项似乎可以工作,但它需要在Reader中执行所有操作第二个选项似乎可以,但我不确定计算结果是否会一直存储在运行时中,即数组不会被GC扫描并重新初始化。(数组很大,它们的初始化很繁重)。我的推理正确吗?如果正确,哪个选项更好?我承认我可能会错过其他可能性,是否有其他方法或模式来处理预先计算的数据?

q3qa4bjr

q3qa4bjr1#

如果在顶层定义未装箱的ArrayVector

myData :: VU.Vector Int
myData = ...any definition...

字符串
那么只要myData被强制为WHNF,所有的值将被完全计算,并且对myData的元素的所有访问将使用预先计算的值。
如果你不手动强制,那么当myData的元素在程序中的任何地方被第一次访问时,所有的值都将被预先计算。这可能就足够了。否则,你可以在IO monad中用evaluate强制它。下面的测试程序说明了这种方法。你应该观察到Loading myData...DONE之间的延迟,但是在访问预先计算的元素时没有进一步的延迟。

import Control.Exception
import qualified Data.Vector.Unboxed as VU

myData :: VU.Vector Int
myData = VU.generate 1000000000 (*2)

main = do
  putStrLn "Loading myData..."
  evaluate myData
  putStrLn "DONE"
  print $ myData VU.! 10
  print $ myData VU.! 999999999


如果你需要在初始化中使用ST monad,也可以。只需在myData中完成所有ST的工作,并返回最终的不可变向量。例如,将上面程序中的myData替换为以下内容即可:

import qualified Data.Vector.Unboxed as VU
import qualified Data.Vector.Unboxed.Mutable as VUM
import Control.Monad.ST

myData :: VU.Vector Int
myData = runST $ do
  v <- VUM.generate 1000000000 id
  VUM.mapM_ (\x -> pure (x*2)) v
  VU.freeze v

相关问题