我正在編寫一個程序,它爲目錄中的每個映像文件創建一個包含一個命令的shell腳本。目錄中有667,944張圖片,所以我需要正確處理嚴格性/懶惰問題。堆棧空間溢出(可能與mapM有關)
下面是一個簡單的例子,它給我Stack space overflow
。如果我使用+RTS -Ksize -RTS
給它更多的空間,它確實有效,但是應該能夠在內存很小的情況下運行,立即生成輸出。所以我一直在閱讀關於Haskell wiki和Haskell上的wikibook的嚴格內容,試圖找出如何解決這個問題,並且我認爲它是mapM命令之一,它讓我感到悲傷,但我仍然對解決問題的嚴格程度不夠了解。
我發現了一些其他問題似乎相關(Is mapM in Haskell strict? Why does this program get a stack overflow?和Is Haskell's mapM not lazy?),但啓發仍然沒有我。
import System.Environment (getArgs)
import System.Directory (getDirectoryContents)
genCommand :: FilePath -> FilePath -> FilePath -> IO String
genCommand indir outdir file = do
let infile = indir ++ '/':file
let angle = 0 -- have to actually read the file to calculate this for real
let outfile = outdir ++ '/':file
return $! "convert " ++ infile ++ " -rotate " ++ show angle ++
" -crop 143x143+140+140 " ++ outfile
main :: IO()
main = do
putStrLn "#!/bin/sh"
(indir:outdir:_) <- getArgs
files <- getDirectoryContents indir
let imageFiles = filter (`notElem` [".", ".."]) files
commands <- mapM (genCommand indir outdir) imageFiles
mapM_ putStrLn commands
編輯:TEST#1
這裏的例子的最新版本。我使用ghc --make -O2 amy2.hs -rtsopts
命令編譯它。如果我用命令./amy2 ~/nosync/GalaxyZoo/table2/images/ wombat
運行它,我得到
TEST 1
Stack space overflow: current size 8388608 bytes.
Use `+RTS -Ksize -RTS' to increase it.
如果我不是用命令./amy2 ~/nosync/GalaxyZoo/table2/images/ wombat +RTS -K20M
運行它,我得到正確的輸出...最後:
TEST 1
667946
convert /home/amy/nosync/GalaxyZoo/table2/images//587736546846572812.jpeg -rotate 0 -crop 143x143+140+140 wombat/587736546846572812.jpeg
convert /home/amy/nosync/GalaxyZoo/table2/images//587736542558617814.jpeg -rotate 0 -crop 143x143+140+140 wombat/587736542558617814.jpeg
...等上。
'genCommand'實際上是在做任何I/O嗎?爲什麼使用'mapM'如果'map'可以工作? –
在這個例子中,genCommand實際上並沒有做任何IO。但在我的真實應用程序中,genCommand將讀取該文件,以計算在其生成的命令中使用的適當參數。所以我想我需要使用mapM。 – mhwombat
嘗試用'safeMapM'替換'mapM' from http://stackoverflow.com/questions/15546216/is-using-mapm-sequence-considered-good-practice –