IO (возможно изображение) -> изображение
Я создаю игру с Gloss. У меня есть эта функция:
block :: IO (Maybe Picture)
block = loadJuicyPNG "block.png"
Как мне взять этот IO (возможно изображение) и превратить его в изображение?
2 ответа
Вам необходимо связать значение. Это делается либо с помощью функции связывания (>>=)
или do
-notation:
main :: IO ()
main = do
pic <- block
case pic of
Just p -> ... -- loading succeeded, p is a Picture
Nothing -> ... -- loading failed
Это Maybe Picture
потому что загрузка может произойти сбой, и вы должны как-то обработать этот возможный сбой.
Это в основном тот же ответ, что и у Бартека, но с использованием другого подхода.
Допустим, у вас есть функция foo :: Picture -> Picture
преобразовывает картину в некотором роде. Это ожидает Picture
в качестве аргумента, но все, что у вас есть, это block :: IO (Maybe Picture)
; там может быть или не быть картина, похороненная там, но это все, что у вас есть.
Для начала предположим, что у вас есть какая-то функция foo' :: Maybe Picture -> Maybe Picture
, Это определение просто:
foo' :: Maybe Picture -> Maybe Picture
foo' = fmap foo
На самом деле так просто, что ты никогда не пишешь этого; где бы вы ни использовали foo'
Вы просто используете fmap foo
непосредственно. Как вы помните, эта функция выполняет возврат Nothing
если получится Nothing
, и вернуться Just (foo x)
если он получает какое-то значение Just x
,
Теперь, учитывая, что у вас есть foo'
как применить его к значению, скрытому в IO
тип? Для этого мы будем использовать Monad
например IO
, который предоставляет нам две функции (типы здесь специализируются на IO
):
return :: a -> IO a
(>>=) :: IO a -> (a -> IO b) -> IO b
В нашем случае мы признаем, что оба a
а также b
являются Maybe Picture
, Если foo' :: Maybe Picture -> Maybe Picture
, затем return . foo' :: Maybe Picture -> IO (Maybe Picture)
, Это означает, что мы можем, наконец, "применить" foo
к нашей картине:
> :t block >>= return . (fmap foo)
block >>= return . (fmap foo) :: IO (Maybe Picture)
Но мы на самом деле не применяем foo
сами. То, что мы действительно делаем, это лифтинг foo
в контекст, где однажды block
выполняется, foo'
можно вызвать на что угодно block
производит.