1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
-- 1. Add the WriterT transformer to the App monad transformer stack. Modify
-- runApp to work with this new setup.
--
-- 2. Rewrite the constrainedCount function to record results using the WriterT
-- transformer in your new App stack.
{-- From examples/examples/ch18/UglyStack.hs and modified --}
import CountEntries (listDirectory)
-- System.Directory also has listDirectory function. Hide it to not conflict
-- with our version from CountEntries module.
import System.Directory hiding (listDirectory)
import System.FilePath
import Control.Monad -- Needed for the forM_ and 'when'
import Control.Monad.Reader
import Control.Monad.State
import Control.Monad.Writer
data AppConfig = AppConfig {
cfgMaxDepth :: Int
} deriving (Show)
data AppState = AppState {
stDeepestReached :: Int
} deriving (Show)
type App = WriterT [(FilePath, Int)] (ReaderT AppConfig (StateT AppState IO)) ()
runApp :: App -> Int -> IO (((), [(FilePath, Int)]), AppState)
runApp k maxDepth =
let config = AppConfig maxDepth
state = AppState 0
in runStateT (runReaderT (runWriterT k) config) state
constrainedCount :: Int -> FilePath -> App
constrainedCount curDepth path = do
contents <- liftIO . listDirectory $ path
tell [(path, length contents)]
cfg <- ask
forM_ contents $ \name -> do
let newPath = path </> name
isDir <- liftIO $ doesDirectoryExist newPath
if isDir && curDepth < cfgMaxDepth cfg
then do
let newDepth = curDepth + 1
st <- get
when (stDeepestReached st < newDepth) $
put st { stDeepestReached = newDepth }
constrainedCount newDepth newPath
else return ()
{-- End of code from examples --}
-- ghci> :l 18_a_2.hs
-- [1 of 3] Compiling CountEntries ( CountEntries.hs, interpreted )
-- [2 of 3] Compiling Main ( 18_a_2.hs, interpreted )
-- Ok, two modules loaded.
-- ghci> runApp (constrainedCount 0 "../ch08") 2
-- (((),[("../ch08",12),("../ch08/test-8_b_3",3),("../ch08/test-8_b_3/dir1",7),("../ch08/test-8_b_3/dir2",1)]),AppState {stDeepestReached = 2})
|