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.
Monads.
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
maybeRead :: Read a => String -> Maybe a
maybeRead s = case reads s of
[(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)
maybeRead :: Read a => String -> Maybe a
maybeRead s = case reads s of
[(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".)
print $ sum $ map read input
\$\endgroup\$