This code is hella slow and consumes ludicrous amounts of memory.
But why ? Laziness shouldn't be a problem since we are using foldl'
.
import Data.List
import Data.Char
simpleFold :: FilePath -> IO (Int, Int, Int)
simpleFold fp = do
countFile <$> readFile fp
countFile :: String -> (Int, Int, Int)
countFile s =
let (cs, ws, ls, _) = foldl' go (0, 0, 0, False) s
in (cs, ws, ls)
where
go :: (Int, Int, Int, Bool) -> Char -> (Int, Int, Int, Bool)
go (cs, ws, ls, wasSpace) c =
let addLine | c == '\n' = 1
| otherwise = 0
addWord | wasSpace = 0
| isSpace c = 1
| otherwise = 0
in (cs + 1, ws + addWord, ls + addLine, isSpace c)
foldl'
is only strict up to WHNF, it'll be strict in the structure of the tuple accumulator, but not the actual values!
How to solve it ? BangPattern (forcing evaluation seq
)
{-# LANGUAGE BangPatterns #-}
...
go :: (Int, Int, Int, Bool) -> Char -> (Int, Int, Int, Bool)
go (!cs, !ws, !ls, !wasSpace) c =
let addLine | c == '\n' = 1
| otherwise = 0
addWord | wasSpace = 0
| isSpace c = 1
| otherwise = 0
in (cs + 1, ws + addWord, ls + addLine, isSpace c)