0

问题:

如何为需要“SDL.Surface”的函数提供“IO SDL.Surface”?

我宁愿重新考虑我的整个方法,也不愿诉诸使用“unsafePerformIO”之类的东西,除非这实际上是使用它的正确时间(我对此表示怀疑)。

更多信息:

我有一个填充了数字和文件路径的文件,我已经解析了这个文件并将位于这些路径的图像加载到列表 [(Int, IO SDL.Surface)] 中。问题是,SDL.blitSurface函数需要一个正常的 SDL.Surface。

错误信息:

Couldn't match type `IO SDL.Surface'
              with `GHC.ForeignPtr.ForeignPtr SDL.SurfaceStruct'
Expected type: SDL.Surface
Actual type: IO SDL.Surface

我不确定是否需要源代码来回答这个问题,但我还是会提供一些以防万一:

要加载我使用的图像文件:

loadImage :: FilePath -> IO SDL.Surface
loadImage [] = error "empty list"
loadImage a =
  SDL.loadBMP a

要创建我使用的数字和图像列表:

createIDImageList :: [Tiletype] -> [(Int, IO SDL.Surface)]
createIDImageList a =
  if null a then []
  else [(tiletypeid $ a !! 0, loadImage (C8.unpack ( tiletypeimage ( a !! 0))))] ++ createIDImageList (tail a)

为了从这个列表中检索正确的图片,我使用了这个函数:

imageFromID :: Int -> [(Int, IO SDL.Surface)] -> Maybe (IO SDL.Surface)
imageFromID a b =
  if null b then Nothing
  else if a == (fst $ b !! 0) then Just (snd $ b !! 0)
  else imageFromID a (tail b)

最后我使用带有 SDL.blitSurface 的 imageFromID 来绘制图像,但由于 IO 的原因我不能。

4

2 回答 2

2

任何时候你最终得到的[IO Foobar],你可能想要的实际上是IO [Foobar]。该sequence函数将一个转换为另一个。或者,您可以在首先创建列表时使用mapM而不是。map

在您的示例中,它有点复杂,因为我们有[(Int, IO Surface)]. 让我看看我能建议什么...

loadImage是一个 I/O 动作。它接受一个文件名并返回一个 IO 操作来加载图像。你的createIDImageList功能真的

createIDImageList = map f
  where
    f a = (tiletypeid a, loadImage (C8.unpack ( tiletypeimage a) ) )

您可能想要做的是更改f为拥有 typeIO (Int, Surface)而不是(Int, IO Surface). 然后你可以mapM f,产生一个返回内容列表的 I/O 操作。

createIDImageList :: [Tiletype] -> IO [(Int, SDL.Surface)]
createIDImageList = mapM f
  where
    f a = do
      surface <- loadImage (C8.unpack (tiletypeimage a) )
      return (tiletypeid a, surface)

关于imageFromID:你可能想要做的是这样的:

main = do
  images <- createIDImageList (...)
  ...
  let image5 = imageFromID 5 images
  SDL.blitSurface image5 ...

then的类型imageFromID变为

imageFromID :: `Int -> [(Int, SDL.Surface)] -> Maybe SDL.Surface

(由于images现在有 type [(Int, SDL.Surface)],其中没有IO,多亏了<-。)

您在这里所做createIDImageList的实际上是从磁盘上加载所有内容,然后您可以imageFromID在想要获得感兴趣的表面时使用(其中没有 I/O)。

于 2014-12-22T11:50:59.060 回答
0
do image <- loadImage "imagefile"
   blitSurface image rect1 dest rect2
于 2014-12-22T11:51:00.973 回答