【问题标题】:IO (Maybe Picture) -> PictureIO(可能是图片)-> 图片
【发布时间】:2019-05-09 09:06:21
【问题描述】:

我正在使用 Gloss 创建游戏。 我有这个功能:

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

如何获取这个 IO(Maybe Picture)并将其变成图片?

【问题讨论】:

  • 从技术上讲,您有一个IO 操作,而不是一个函数。您调用loadJuicyPNG,它会返回一个IO 操作,当执行该操作时,可能会导致Picture
  • 一旦你在IO monad 中工作,你(通常)并不打算摆脱它。无论您想对生成的Picture(如果有)应用什么操作,都应该在IO monad 中应用。也许你应该在你的问题中澄清你想用那张图片做什么......
  • 顺便说一句,在这种情况下,您可能还对 monad 转换器感兴趣,例如 MaybeT IO PictureA good read here
  • 一个IO (Maybe Picture) -> Picture类型值不能存在,但IO (IO (Maybe Picture)) -> IO Picture可以。
  • @WillNess dontDoThis :: IO (Maybe Picture) -> Picture dontDoThis = fromJust . unsafePerformIO。从技术上讲,它可以存在;这几乎可以肯定是个坏主意。

标签: haskell gloss juicy-pixels


【解决方案1】:

你需要绑定这个值。这可以通过绑定函数(>>=)do-notation 完成:

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

这是一个Maybe Picture,因为加载可能会失败,您必须以某种方式处理这种可能的失败。

【讨论】:

  • 我仍然无法使用我在其他功能上加载的图片。我该怎么做?
  • @BrunoPinto 你能说得更具体点吗?例如,如果你有一个函数foo :: Picture -&gt; String,你就写foo p
  • 这很难解释,所以如果你不能帮助我,我理解,但基本上我需要在 IO 之外的几个函数中使用图片,我不知道该怎么做.我不确定在Just p -&gt;Nothing -&gt; 前面写什么,所以这可能是我在这里缺少的。
  • Just p -&gt; ... 之后,您只需编写一些使用p 的常规纯代码。请记住,最终,整个do 块会创建一个封装 其他代码的IO 操作。换句话说,如果你在这里写... Just p -&gt; foo p,不要认为这是立即在Picture 上运行foo;相反,您正在创建一个 IO 动作,当 Haskell 运行时执行它时,它会从 block 动作中提取 pic 并在其上调用 foo 你。
  • @BrunoPinto 可以调用其他没有IO 的函数来代替三个点;在 IO 中使用纯函数很好,否则就不行了。因此,您的加载必须始终驻留在 main 中,然后使用它的代码必须跟随,当您考虑时,这是有道理的。
【解决方案2】:

这与 Bartek 的答案基本相同,但使用了不同的方法。

假设您有一个函数foo :: Picture -&gt; Picture 以某种方式转换图片。它需要 Picture 作为参数,但你所拥有的只是 block :: IO (Maybe Picture);里面可能有也可能没有图片,但它就是你所拥有的一切。

首先,假设您有一些函数foo' :: Maybe Picture -&gt; Maybe Picture。它的定义很简单:

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

实际上如此简单,以至于您从未真正编写过它;无论你在哪里使用foo',你都可以直接使用fmap foo。这个函数的作用,你会记得,如果它得到Nothing,则返回Nothing,如果它得到一些值Just x,则返回Just (foo x)

现在,假设你有foo',你如何将它应用到埋在IO 类型中的值?为此,我们将使用IOMonad 实例化,它为我们提供了两个函数(这里的类型专门用于IO):

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

在我们的例子中,我们认识到ab 都是Maybe Picture。如果foo' :: Maybe Picture -&gt; Maybe Picture,那么return . foo' :: Maybe Picture -&gt; IO (Maybe Picture)。这意味着我们终于可以将foo“应用”到我们的图片上:

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

但我们自己并没有真正应用foo。我们真正所做的是将foo 提升到一个上下文中,一旦block 被执行,foo' 就可以在block 产生的任何东西上被调用。

【讨论】:

    猜你喜欢
    • 2019-03-24
    • 2017-10-23
    • 2017-01-27
    • 1970-01-01
    • 1970-01-01
    • 2014-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多