HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Unix tail in haskell

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
tailunixhaskell

Problem

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 ++ "  [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)

Solution

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 ++ " [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

Code Snippets

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

Context

StackExchange Code Review Q#29732, answer score: 2

Revisions (0)

No revisions yet.