评估高阶函数

时间:2017-02-19 17:08:29

标签: haskell lazy-evaluation

我编写了一个函数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个样本。 enter image description here 如果我对此问题做了一些小修改并首先映射或过滤它,结果就不同了:

main = do
    [file] <- getArgs
    samples <- getSamplesFromFile file
    let slice = V.slice 0 50000 samples
    let mapped = V.map id slice
    print mapped

这样,似乎并非每个样本都加载到内存中,只有片段: enter image description here 为了确保这种情况,我再次使用一半大小的片段(25000个样本)运行程序: enter image description here 现在,内存使用量似乎与切片的大小成比例。仅仅因为我用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)

如果我执行以下操作,我不会遇到奇怪的行为:

  1. 通过mkdir
  2. 在某处创建新目录
  3. 将上述Main.hs添加到目录。
  4. 使用ghc Main.hs -O2 -rtsopts -prof进行编译。
  5. 通过./Main myfile.wav +RTS -hy运行。
  6. 使用hp2psps2pdf创建pdf。
  7. 如果我执行以下操作,我确实会遇到奇怪的行为:

    1. 通过mkdir laziness创建一个新目录 laziness
    2. 通过cabal启动cabal init项目。
    3. 将上述Main.hs添加到/src
    4. ghc-options: -O2 -rtsopts -prof添加到laziness.cabal
    5. 使用cabal install
    6. 进行编译
    7. 通过laziness myfile.wav +RTS -hy
    8. 运行
    9. 使用hp2psps2pdf创建pdf。
    10. 如果我:

      ,我甚至会遇到奇怪的行为
      1. cd laziness/src
      2. 使用ghc Main.hs -O2 -rtsopts -prof进行编译。
      3. 通过./Main myfile.wav +RTS -hy运行。
      4. 使用hp2psps2pdf创建pdf。
      5. 所以看起来这种行为只发生在代码在cabal项目中时。这对我来说似乎很奇怪。这可能与我的cabal项目的设置有关吗?。

0 个答案:

没有答案