Midway
Midway

Reputation: 55

recursive function that prints something

I have a list of type [Int] which can only contain two values: 0 or 1.

Example : [0, 0, 1, 1, 0, 0]

I would like to iterate through this list and when the current element is a 0, print '_' and if it is a 1 print '*'.

For the previous list, here is the result on the standard output :

__**__

I think that I have to do something like that :

displayLine :: [Int] -> IO [Int]
displayLine (0 : xs) =
    do
        print '_'
        -- next char
displayLine (1 : xs) =
    do
        print '*'
        -- next char

How can I display a character and continue recursion with the next character?

Upvotes: 3

Views: 247

Answers (2)

Hans Lub
Hans Lub

Reputation: 5678

The nice thing about do-notation is that the code usually looks just like it would in an imperative language (only better) : a couple of statements and a return at the end:

displayLine (0 : xs) =  do
    print '_'
    ys <- displayLine xs -- ys will be identical to xs,
    return (0:ys)

Don't forget to add a case for displayLine [], unless all of your lists are infinite....

BTW, do you really need to return anything, as the list is returned unchanged? If not, the type of displayLine could be [Int] -> IO () and the definition could be even simpler..

Upvotes: 2

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476557

You call displayLine with the tail of the list. But here the type will be IO (), not IO [Int] since the action does not return anything:

displayLine :: [Int] -> IO ()
displayLine (0 : xs) = do
        print '_'
        displayLine xs
displayLine (1 : xs) = do
        print '*'
        displayLine xs

You probably also want to use putChar :: Char -> IO () to print a single char, since print will call show and thus print a Char literal, and a new line.

This however duplicates logic. We can make use of mapM_ :: (Foldable f, Monad m) => (a -> m b) -> f a -> m () to perform a mapping where each element performs a monadic action:

displayLine :: [Int] -> IO ()
displayLine = mapM_ (putChar . f)
    where f 0 = '_'
          f 1 = '*'

For example:

Prelude> displayLine [0,1,1,0,1,0] >> putStrLn ""
_**_*_

The putStrLn "" at the end is used to start a new line after the characters have been printed.

Upvotes: 5

Related Questions