IO (Maybe Picture) -> Picture

596 views Asked by At

I'm creating a game with Gloss. I have this function :

block :: IO (Maybe Picture)
block = loadJuicyPNG "block.png"

How do I take this IO (Maybe Picture) and turn it into a Picture?

2

There are 2 answers

5
Bartek Banachewicz On BEST ANSWER

You need to bind the value. This is done either with the bind function (>>=), or by do-notation:

main :: IO ()
main = do
    pic <- block
    case pic of
        Just p -> ...   -- loading succeeded, p is a Picture
        Nothing -> ...  -- loading failed

It is a Maybe Picture because the loading might fail, and you have to handle that possible failure somehow.

0
chepner On

This is basically the same answer as Bartek's, but using a different approach.

Let's say you have a function foo :: Picture -> Picture the transforms a picture in some way. It expects a Picture as an argument, but all you have is block :: IO (Maybe Picture); there may or may not be a picture buried in there, but it's all you have.

To start, let's assume you have some function foo' :: Maybe Picture -> Maybe Picture. It's definition is simple:

foo' :: Maybe Picture -> Maybe Picture
foo' = fmap foo

So simple, in fact, that you never actually write it; wherever you would use foo', you just use fmap foo directly. What this function does, you will recall, is return Nothing if it gets Nothing, and return Just (foo x) if it gets some value Just x.

Now, given that you have foo', how do you apply it to the value buried in the IO type? For that, we'll use the Monad instanced for IO, which provides us with two functions (types here specialized to IO):

return :: a -> IO a
(>>=) :: IO a -> (a -> IO b) -> IO b

In our case, we recognize that both a and b are Maybe Picture. If foo' :: Maybe Picture -> Maybe Picture, then return . foo' :: Maybe Picture -> IO (Maybe Picture). That means we can finally "apply" foo to our picture:

> :t block  >>= return . (fmap foo)
block  >>= return . (fmap foo) :: IO (Maybe Picture)

But we aren't really applying foo ourselves. What we are really doing is lifting foo into a context where, once block is executed, foo' can be called on whatever block produces.