-- generates names in the following order
-- a, b, c ... z, aa, ba, ca, ... za, ab, bb, cb ...
nextName :: String -> String
nextName [] = "a"
nextName (x:xs) = if x == 'z' then 'a' : nextName xs else succ x : xs
-- verify if the number of names generated is as expected.
countNames :: String -> String -> Int
countNames start end = loop 1 start
where
loop acc next =
if next == end then
acc
else
loop (acc + 1) (nextName next)
在ghci中运行countNames "a" "zzzzzz"
在我的com上运行它会占用整个内存并花费大量时间来完成。
如果有人说明空间泄漏发生的地点和原因,请表示赞赏吗?答案 0 :(得分:8)
问题是一个大的计数器thunk因为计数器acc
上的循环不严格。通常的解决方案是使用seq
或BangPatterns
来严格限制。以下是使用BangPatterns
的解决方案。
{-# LANGUAGE BangPatterns #-}
-- generates names in the following order
-- a, b, c ... z, aa, ba, ca, ... za, ab, bb, cb ...
nextName :: String -> String
nextName [] = "a"
nextName (x:xs) = if x == 'z' then 'a' : nextName xs else succ x : xs
-- verify if the number of names generated is as expected.
countNames :: String -> String -> Int
countNames start end = loop 1 start
where
loop !acc next =
if next == end then
acc
else
loop (acc + 1) (nextName next)
答案 1 :(得分:5)
虽然使用严格的评估修复了您的问题,但我建议您重复使用标准函数来计算间隔长度:
countNames :: String -> String -> Int
countNames start end = (+) 1 . length . takeWhile (/= end) $ iterate nextName start
说明:
iterate
生成nextName
:[start, nextname start, nextname (nextName start), ...]
; takeWhile (/= end)
保留列表元素,直到达到预期值(不包括上限); length
并加1。