5
\$\begingroup\$

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
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

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
answered Oct 12, 2013 at 16:30
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.