Challenge 2: A Pure Core With a Thin IO Shell — Possible Solution ==================================================================== Main.hs: calculateTotal :: [Int] -> Int -- completely free of IO calculateTotal = sum main :: IO () main = do line <- getLine let numbers = map read (words line) :: [Int] total = calculateTotal numbers putStrLn ("Total: " ++ show total) Sample run (input: "3 5 7 10"): Total: 25 Explanation: calculateTotal's type, [Int] -> Int, contains no IO anywhere -- it's a pure function, fully testable on its own with an ordinary function call like calculateTotal [3, 5, 7, 10], no IO mocking or setup required at all. All the actual IO -- reading the line, parsing it, printing the result -- lives entirely inside main's own do block, which is the thin shell responsible for getting real-world input to the pure core and printing its result back out. calculateTotal itself never touches getLine, putStrLn, or anything IO-flavored. WHY THIS WORKS AS AN ANSWER ------------------------------ This implements the exact pure-core/IO-shell pattern the chapter recommends, with calculateTotal kept genuinely free of IO in its own type while main handles all the actual reading and printing around it.