Haskell -- problem with pretty-printing a list
fizzbuzz, haskell, pretty-print
Solution
map :: (a -> b) -> [a] -> [b]
putStrLn :: Show a => a -> IO ()
map putStrLn :: Show a => [a] -> [IO ()]
You've got a list of `IO ()` actions.
main :: IO ()
You need to join them into a single `IO ()` action.
What you want to do is to perform each of those `IO ()` actions in sequence/sequence_:
sequence :: Monad m => [m a] -> m [a]
sequence_ :: Monad m => [m a] -> m ()
For convenience, mapM/mapM_ will map a function over a list and sequence the resulting monadic results.
mapM :: Monad m => (a -> m b) -> [a] -> m [b]
mapM_ :: Monad m => (a -> m b) -> [a] -> m ()
So your fixed code would look like this:
main = mapM_ putStrLn $ map fizzBuzz [1..100]
Although I'd probably write it like this:
main = mapM_ (putStrLn . fizzBuzz) [1..100]
Or even this:
main = putStr $ unlines $ map fizzBuzz [1..100]
Let's write our own `sequence`. What do we want it to do?
sequence [] = return []
sequence (m:ms) = do
x <- m
xs <- sequence ms
return $ x:xs
- If there's nothing left in the list, return (inject into the monad) an empty list of results.
- Otherwise, within the monad,
- Bind (for the `IO` monad, this means execute) the first result.
- `sequence` the rest of the list; bind that list of results.
- Return a cons of the first result and the list of other results.
GHC's library uses something more like `foldr (liftM2 (:)) (return [])` but that's harder to explain to a newcomer; for now, just take my word that they're equivalent.
`sequence_` is easier, since it doesn't bother keeping track of the results. GHC's library implements it as `sequence_ ms = foldr (>>) (return ()) ms`. Let's just expand the definition of `foldr`:
sequence [a, b, c, d]
= foldr (>>) (return ()) [a, b, c, d]
= a >> (b >> (c >> (d >> return ())))
In other words, "do `a`, discard the result; do `b`; discard the result, … finally, return `()`".
mapM f xs = sequence $ map f xs
mapM_ f xs = sequence_ $ map f xs
On the other hand, you don't even need to know monads at all with the alternate `unlines` solution.
What does `unlines` do? Well, `lines "a\nb\nc\nd\n" = ["a", "b", "c", "d"]`, so of course `unlines ["a", "b", "c", "d"] = "a\nb\nc\nd\n"`.
`unlines $ map fizzBuzz [1..100]` = `unlines ["1", "2", "Fizz", ..]` = `"1\n2\nFizz\n..."` and off it goes to `putStr`. Thanks to the magic of Haskell's laziness, the full string never needs to be constructed in memory, so this will happily go to `[1..1000000]` or higher :)
Problem
I'm new to haskell, and i read through and digested Learn You A Haskell For Great Good, trying out a couple of things along the way. For my first project i wanted to try the classic: FizzBuzz. So i came up with the following code: ``` import System.IO fizzBuzz :: (Integral a) => a -> String fizzBuzz num | fizz && buzz = "FizzBuzz" | fizz = "Fizz" | buzz = "Buzz" | otherwise = show num where fizz = num `mod` 3 == 0 buzz = num `mod` 5 == 0 main = print $ map fizzBuzz [1..100] ``` Worked great, except i got a rather dense looking list that was hard to read. So i tried this main function instead: ``` main = map putStrLn $ map fizzBuzz [1..100] ``` And that gives me the error `Couldn't match expected type 'IO t' against inferred type '[IO ()]'`. I tried half a dozen things and none of it seemed to help. What's the proper way to do what i'm trying to do?