Haskell在一个不期望它的函数上使用IO

时间:2014-12-22 11:38:05

标签: haskell sdl io-monad

问题:

如何为需要“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而使用。

2 个答案:

答案 0 :(得分: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更改为IO (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 ...

然后imageFromID的类型变为

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

(因为images现在有[(Int, SDL.Surface)]类型,其中没有IO,感谢<-。)

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

答案 1 :(得分:0)

do image <- loadImage "imagefile"
   blitSurface image rect1 dest rect2