\$\begingroup\$
\$\endgroup\$
I am trying to write a simple version of the unix tail utility in haskell to improve my understanding of monads. Here is what I have now. I am pretty sure that this is not quite "Haskell enough" yet. Can you please help me improve my code?
import System.Environment
import System.Exit
import Control.Monad
main = getArgs >>= (parse' (10, [])) >>= \ (n_lines, ss) ->
putStr $ concatMap (tailFile n_lines) ss
tailFile :: Int -> (FilePath, String) -> String
tailFile n_lines (f, c) =
"==> " ++ f ++ " <==\n" ++
(unlines.reverse.(take n_lines).reverse.lines) c
parse' :: (Int, [(FilePath, String)])
-> [String]
-> IO (Int, [(FilePath, String)])
parse' _ ("-h":_) = putStrLn "usage: " >> exit
parse' _ ("-v":_) = putStrLn "version: 0.1" >> exit
parse' (_, ss) ("-n":num:f) = parse' (read num, ss) f
parse' (n, ss) (f:fs) = do
contents <- readFile f
parse' (n, ss ++ [(f,contents)]) fs
parse' (x, ss) [] = return (x, ss)
exit = exitWith ExitSuccess
die = exitWith (ExitFailure 1)
asked Aug 14, 2013 at 13:21
1 Answer 1
\$\begingroup\$
\$\endgroup\$
My first approach is to map the arguments to a list of IO actions and then execute them:
import Control.Monad
import System.Environment
lastLines :: Int -> String -> [String]
lastLines n = reverse.take n.reverse.lines
printLines :: [String] -> IO ()
printLines = flip forM_ $ putStrLn
readLastLines :: Int -> FilePath -> IO [String]
readLastLines n f = readFile f >>= return . (++) ["==>" ++ f ++ "<=="] . lastLines n
argsToActions :: [String] -> [IO ()]
argsToActions ("-h":_) = [print "Usage"]
argsToActions ("-v":_) = [print "V 1.0"]
argsToActions ("-n":n:f:_) = [readLastLines (read n) f >>= printLines]
argsToActions (f:fs) = [readLastLines 10 f >>= printLines] ++ argsToActions fs
argsToActions [] = []
main :: IO ()
main = getArgs >>= sequence_ . argsToActions
lang-hs