Skip to content

Instantly share code, notes, and snippets.

@bor0
Last active August 29, 2015 14:02
Show Gist options
  • Save bor0/da511c3891a875ceeb71 to your computer and use it in GitHub Desktop.
Save bor0/da511c3891a875ceeb71 to your computer and use it in GitHub Desktop.
CountLinesOfCode
import System.Directory
import Control.Monad (filterM, mapM, liftM)
import System.FilePath ((</>))
getDirsRec :: FilePath -> IO [FilePath]
getDirsRec d = do
dirContents <- getDirectoryContents d
let dirContents' = [ d </> x | x <- dirContents, x /= ".", x /= ".." ]
dirs' <- mapM dirRec dirContents'
return (concat dirs' ++ [d])
where
dirRec n = do
isDir <- doesDirectoryExist n
if isDir then getDirsRec n
else return []
getFiles :: FilePath -> IO [FilePath]
getFiles d = do
dirContents <- getDirectoryContents d
filterM doesFileExist (map (d </>) dirContents)
getLOC :: FilePath -> IO Int
getLOC f = (length . lines) `fmap` readFile f
main = liftM sum (getDirsRec "." >>= mapM getFiles >>= mapM getLOC . concat)
@bor0
Copy link
Author

bor0 commented Jun 10, 2014

<frerich> boR0: I think a good improvement would be to not implement the directory walking yourself. Instead, use System.FilePath.Find.fold
<frerich> bor0: Something like 'find always (acc f -> acc + linesInFile f) "."'
<BoR0> frerich, I thought such function existed, but I was gonna play around with IO and experiment stuff
<frerich> bor0: Ah, well - if you are more looking for 'coding style' commentary. The first few things which came to my head when reading your paste were 1. "Why use filterM instead of plain filter?", "dirs ++ ds" will be somewhat inefficient if 'dirs' is large and "foldingFunction" is not a terribly nice name for a function.
<frerich> Oh, I forgot to insert 2. and 3. I guess :)
<BoR0> ok, about 1, how can I use filter instead of filterM for a IO function like doesFileExist?
<frerich> bor0: You can't. That's just the first thought which crossed my mind. :)
<BoR0> ah, okay
<tdammers> you can, sort of, but you'll just end up rewriting filterM with other ...M functions
<frerich> bor0: I think it would be nice to separate this problem into three tasks: 1. Get a list of all files beneath some directory. 2. Getting the lines of text in a file. Then you could do something like "sum . map linesInFile . getFilesBenath $ someDir"
<frerich> bor0: I.e. not mangle it all into once.
<frerich> bor0: ...except that you'd use fmap or instead of 'map' :)
<BoR0> frerich, that's a good suggestion, I'll probably rewrite it that way

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment