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

Probably unneeded returns

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

Problem

This is my first "useful" Haskell program. It's invoked with filenames as arguments where the last filename is the destination to which the content of all other files will be concatenated. As far as I can tell it's working but I don't like the two returns in the main function and would like to know how I can get rid of the do in the concatFiles function.

import System.Environment (getArgs)
import System.IO (hClose, hPutStr, openFile, IOMode(WriteMode))

concatFiles :: FilePath -> [FilePath] -> IO ()
concatFiles destination files = do
    writeHandle <- openFile destination WriteMode
    mapM (writeToDestination writeHandle) files
    hClose writeHandle
    where
        writeToDestination writeHandle file =
            hPutStr writeHandle =<< readFile file

main = do
    args <- getArgs
    argc <- return $ length args
    destination <- return $ last args
    concatFiles destination $ take (argc-1) args

Solution

For your argc

  • Last element (last)



  • Everything but the first (tail)



  • Everything but the last (init)



So with
init we can eliminate the need for argc, changing your main to

main = do
    args <- getArgs
    let destination = last args
    concatFiles destination $ init args


But really, the word
destination is longer than the function call last args, and doesn't really add much clarity, so we can change that, too, removing the need for the let entirely!

main = do
    args <- getArgs
    concatFiles (last args) (init args)


And if you really wanted to become more intimately familiar with how
do notations and monads in general work, we can actually remove the do notation and replace it with a >>= operator by doing

main = getArgs >>= \args -> concatFiles (last args) (init args)


So as a quick recap of what is happening here, we are calling
getArgs, which returns a list of arguments wrapped in the IO monad. The >>= (bind) operator takes that IO value, extracts the value inside, and sends it into the function on the right side of the >>= operator, where it gets bound to the argument args`.

Code Snippets

binding <- value wrapped in whatever monad you're using
let argc = length args
    destination = last args
main = do
    args <- getArgs
    let destination = last args
    concatFiles destination $ init args
main = do
    args <- getArgs
    concatFiles (last args) (init args)
main = getArgs >>= \args -> concatFiles (last args) (init args)

Context

StackExchange Code Review Q#44799, answer score: 10

Revisions (0)

No revisions yet.