# Extracting an integer command-line argument and printing a sum of numbers up to that limit

The below code works fine but I have the feeling that there must be something more idiomatic way to do this within the do-notation without having to resort to the two liftMs?

main = do
n <- (liftM read (liftM head getArgs)) :: IO Int
putStrLN . show $sum [1..n]  If I do: main = do args <- getArgs arg1 <- head args n <- read arg1 :: IO Int putStrLn . show$ sum [1..n]


I get:

Expected type: String
Actual type: Char
In the first Argument of 'read', namely 'arg1'


which I do not understand. <- getArgs returns IO [String], so <- head args should return IO String, but it seems to return IO Char?! (as per error message).

So my two questions are:

1. what is the most idiomatic way do do this
2. what's wrong in the second version?
• main = do [n] <- getArgs; print $sum [1..read n] Commented Nov 24, 2017 at 21:29 ## 2 Answers I have the Feeling that there must be something more idiomatic way to do this within the do-notation withouth having to resort to the two liftMs? Yes, a single one. liftM is fmap nowadays. It stems from a time when Functor wasn't a superclass for Monad. The Functor laws state that fmap f . fmap g = fmap (f . g)  Therefore, we can simplify liftM read (liftM head getArgs)  to fmap (read . head) getArgs  We end up with main = do n <- fmap (read . head) getArgs :: IO Int putStrLN . show$ sum [1..n]


Also, putStrLn . show is print. If we introduce a small helper function, the code gets more readable:

readFirstElement :: Read a => [String] -> a

sumNaturalUpTo :: Int -> Int
sumNaturalUpTo n = sum [1..n]

main :: IO ()
main = do
n <- readFirstElement <$> getArgs print$ sumNaturalUpTo n


Note that sum [1..n] is n * (n + 1) div 2, though, so we can optimize sumNaturalUpTo to

sumNaturalUpTo n = n * (n + 1) div 2


Alternatively, we can write

main :: IO ()
main = do
args <- getArgs
print $sumNaturalUpTo$ readFirstElement args


Which might be the easiest one to read.

what's wrong in the second version?

args is not a IO … value.

• So (<$>) = fmap? – A Sz Commented Nov 24, 2017 at 20:17 • @ASz Right. I'm sure I had that in a draft., sorry. – Zeta Commented Nov 25, 2017 at 8:28 This is the code you're looking for: main = do args <- getArgs let arg1 = head args let n = (read arg1) :: Int putStrLn . show$ sum [1..n]


Think of the <- operator as "extract". It "pulls" a value out of a monad.

But once you've pulled args out of the IO monad, you've now got a pure list of strings. It's not in the IO monad, so you can't extract from it. let instead just does a pure binding like you're used to in non-monadic code, which is what you need here.