# “Hell Difficulty” Haskell Fast & Hard

I'm a complete neophyte to Haskell with only a smidge of FP experience – I did some Racket programming academically and have written some semi-FP JavaScript professionally, but now I'm trying to learn Haskell (and FP better). So I read Haskell Fast & Hard with no problems up until the last chapter.

Make a program that sums all of its arguments. Hint: use the function getArgs.

I eventually wrote a program that nominally achieves this requirement, but it felt very hacky. For reference, here is a "correct" program by the author that I think I was supposed to model after. It sums the numbers in a comma-delimited string.

import Data.Maybe

[(x,"")]    -> Just x
_           -> Nothing
getListFromString :: String -> Maybe [Integer]
getListFromString str = maybeRead $"[" ++ str ++ "]" askUser :: IO [Integer] askUser = do putStrLn "Enter a list of numbers (separated by comma):" input <- getLine let maybeList = getListFromString input in case maybeList of Just l -> return l Nothing -> askUser -- show main :: IO () main = do list <- askUser print$ sum list

Based on the above approach, I wrote a function to convert the list of argument-strings back into a comma-delimited string so that most of the other functions could work unchanged.

import Data.Maybe
import System.Environment (getArgs)

[(x,"")]    -> Just x
_           -> Nothing
getListFromString :: String -> Maybe [Integer]
getListFromString str = maybeRead $"[" ++ str ++ "]" getArgsAsString :: [String] -> String getArgsAsString [] = "0" getArgsAsString (x:xs) = x ++ "," ++ getArgsAsString xs askUser :: [String] -> [Integer] askUser input = case (getListFromString (getArgsAsString input)) of Just l -> l Nothing -> error "failsauce" main :: IO () main = do input <- getArgs print$ sum (askUser input)

I am trying to stick to the spirit of the exercise and not go too far into library functions that solve the problem for me without teaching me anything (in particular, the author says not to try too hard to understand the syntax of maybeRead), but it feels very wrong to convert a list of strings to a comma-separated string only to split it out again into a maybe-list of integers.

All advice is appreciated! (But educational guidance is appreciated more than "just use xyz lib function".)

• If all you want to do on an invalid input is to raise an error with an inane message, then you can be done with print $sum$ map read input – abuzittin gillifirca Jan 2 '14 at 12:22

There's very little I would salvage from the model code.

1. Converting the arguments list into comma-separated string is a little hackish and not very efficient (nevertheless it works, and I'd be totally OK with it for a quick throw away script). Therefore I would not use getListFromString.
2. askUser is not needed since we're not interacting with the user.

This is how I would implement it:

import System.Environment (getArgs)
putStrLn $maybe "Arguments invalid" (show . sum)$ sequence values
• SuggestIon: instead of using fmap and sequence like that, just use do { values <- getArgs ; putStrLn $…$ mapM readMaybe values }. This is immediately clearer, in my opinion; you only work in one monad at a time. If you prefer pointfree-golf, this can also be written as the one-liner getArgs >>= putStrLn . maybe "Arguments invalid" (show . sum) . mapM readMaybe. – wchargin Nov 26 '15 at 22:32