【问题标题】:Haskell: Stack overflow when finding max on a large listHaskell:在大列表中找到最大值时堆栈溢出
【发布时间】:2015-08-19 19:19:45
【问题描述】:

我有以下problem 1-4 of the Matasano Cryptopals Challenge 的实现,用于在文件中找到一行,该行是与单个字节异或的文本字符串。它适用于大文件,但显示“堆栈空间溢出:当前大小 8388608 字节”。对于提供的文件。

import System.IO
import System.Environment
import Control.Monad
import Data.Bits
import Data.Word
import Data.Maybe
import Data.List hiding (maximumBy)
import Data.Char
import Data.Ord
import Data.Foldable hiding (sum)


hexChars = "0123456789ABCDEF"

hexToBytes :: String -> Maybe [Word8]
{- Converts a hex string into a byte array -}

hexToBytes hexes = hexToBytes' (map toUpper hexes)
hexToBytes' (char1 : char2 : xs) = do
    tail <- hexToBytes' xs
    byte1 <- char1 `elemIndex` hexChars
    byte2 <- char2 `elemIndex` hexChars
    return ((fromIntegral(byte1*16 + byte2) :: Word8) : tail)
hexToBytes' [_] = Nothing
hexToBytes' [] = Just []

maxBy :: Ord b => Foldable f => (a -> b) -> f a -> a
maxBy = maximumBy . comparing

bytesToString :: Integral i => Monad m => m i -> m Char
bytesToString = liftM (chr . fromIntegral)  

isLowercase x = (x >= 'a') && (x <= 'z')

asciiCheck :: Word8 -> Int
asciiCheck x = if (isLowercase . chr . fromIntegral) x then 1 else 0

score = (sum . map asciiCheck)

readLines :: Handle -> IO [String]
readLines handle = do
    eof <- hIsEOF handle
    if eof then
        return []
    else liftM2 (:) (hGetLine handle) (readLines handle)

decode key = map (xor key)

keys = [minBound ..] :: [Word8]

massDecode inputs =
    maxBy score (liftM2 decode keys inputs)

main = do
    hSetEncoding stdout latin1
    args <- getArgs
    handle <- case args of
        [] -> return stdin
        (x:xs) -> openFile x ReadMode
    lines <- readLines handle
    putStrLn $ bytesToString $ massDecode $ catMaybes $ map hexToBytes lines

该程序通过遍历一个列表来工作,该列表包含与每个可能的键异或的每个输入行。我怀疑这个大列表以某种方式导致了溢出,但我认为这不会导致内存问题,因为列表会延迟生成。我认为我对何时评估 thunk 没有足够的了解,无法直观地了解这是如何导致堆栈溢出的。

所以我的问题是:为什么生成或遍历这个列表会导致堆栈溢出?

【问题讨论】:

  • 是的,你的代码会有所帮助 - 在那之前你可以看看this Wiki article dealing with the different folds and their properties
  • foldl' 可能会缓解任何空间问题...
  • 另外,请确保您正在编译优化 (-O2)。
  • @recursion.ninja:我使用 maximumBy 进行折叠。
  • 好吧,因为有人删除了我的答案(诚然没有充实,但我在工作,没有时间完成它),你正在运行的问题有一个很好的解释进入here

标签: performance haskell stack-overflow lazy-evaluation


【解决方案1】:

正如this thread 中所讨论的,我们现在在前奏中列出的maximumBy 并不是最佳性能,原因有很多,好吧,让我们说一下“原因”。

如果您使用建议的 maximumBy' 函数,它是严格的,您可能会修复泄漏:

foldl1' f l = foldl' f (head l) (tail l)

maximumBy' f = foldl1' max'
  where max' x y = case f x y of
                        GT -> y
                        _  -> x

【讨论】:

    猜你喜欢
    • 2011-08-22
    • 2015-06-17
    • 1970-01-01
    • 2016-06-27
    • 2011-11-24
    • 2011-07-26
    • 2013-07-11
    • 2019-07-08
    • 2015-08-05
    相关资源
    最近更新 更多