我编写了一个函数getSamplesFromFile
,它接收一个文件并将其内容作为Vector
Floats
返回。这些函数使用Data.ByteString
将文件内容读入Data.ByteString.hGet
,然后使用以下内容将Data.ByteString
转换为Vector
Floats
import qualified Data.Vector.Unboxed as V
import qualified Data.ByteString as BS
import Data.Word
import System.Environment
import GHC.Int
toVector :: BS.ByteString -> V.Vector Float
toVector bs = vgenerate (fromIntegral (BS.length bs `div` 3)) $ \i ->
myToFloat [BS.index bs (3*i), BS.index bs (3*i+1), BS.index bs (3*i+2)]
where
myToFloat :: [Word8] -> Float
myToFloat = sum . map fromIntegral
vgenerate n f = V.generate n (f . fromIntegral)
我正在通过一个小型测试程序来测试这个程序是多么懒惰:
main = do
[file] <- getArgs
samples <- getSamplesFromFile file
let slice = V.slice 0 50000 samples
print slice
如果我在一个13MB的文件上运行它,似乎每个样本都被加载到内存中,即使我只需要打印50000个样本。 如果我对此问题做了一些小修改并首先映射或过滤它,结果就不同了:
main = do
[file] <- getArgs
samples <- getSamplesFromFile file
let slice = V.slice 0 50000 samples
let mapped = V.map id slice
print mapped
这样,似乎并非每个样本都加载到内存中,只有片段:
为了确保这种情况,我再次使用一半大小的片段(25000个样本)运行程序:
现在,内存使用量似乎与切片的大小成比例。仅仅因为我用id
映射切片。
过滤样本时的结果相同。如何应用高阶函数突然使行为变得懒惰?
修改
问题似乎与cabal
有关。从图片中可以看出,我正在一个名为 laziness 的cabal
项目中测试我的代码。如果在cabal项目之外使用单独的Main.hs
文件,我无法重现这种奇怪的行为。这是我正在使用的Main.hs
:
module Main where
import qualified Data.ByteString as BS
import qualified Data.Vector.Unboxed as V
import Data.Word
import GHC.Int
import System.Environment
main = do
[file] <- getArgs
samples <- getSamplesFromFile file
let slice = V.slice 0 50000 samples
--let filtered = V.filter (>0) slice
let mapped = V.map id slice
print slice
getSamplesFromFile = fmap toVector . BS.readFile
toVector :: BS.ByteString -> V.Vector Float
toVector bs = vgenerate (fromIntegral (BS.length bs `div` 3)) $ \i ->
myToFloat [BS.index bs (3*i), BS.index bs (3*i+1), BS.index bs (3*i+2)]
where
myToFloat :: [Word8] -> Float
myToFloat = sum . map fromIntegral
vgenerate n f = V.generate n (f . fromIntegral)
如果我执行以下操作,我不会遇到奇怪的行为:
mkdir
Main.hs
添加到目录。ghc Main.hs -O2 -rtsopts -prof
进行编译。./Main myfile.wav +RTS -hy
运行。 hp2ps
和ps2pdf
创建pdf。如果我执行以下操作,我确实会遇到奇怪的行为:
mkdir laziness
创建一个新目录 laziness 。cabal
启动cabal init
项目。Main.hs
添加到/src
。ghc-options: -O2 -rtsopts -prof
添加到laziness.cabal
。cabal install
laziness myfile.wav +RTS -hy
。hp2ps
和ps2pdf
创建pdf。如果我:
,我甚至会遇到奇怪的行为cd laziness/src
ghc Main.hs -O2 -rtsopts -prof
进行编译。./Main myfile.wav +RTS -hy
运行。 hp2ps
和ps2pdf
创建pdf。所以看起来这种行为只发生在代码在cabal
项目中时。这对我来说似乎很奇怪。这可能与我的cabal
项目的设置有关吗?。