2014-12-22 64 views
0

問:哈斯克爾在不期望的功能使用IO它

怎麼給一個「IO SDL.Surface」給需要「SDL.Surface」的功能?

我寧願重新思考我的整個方法,而不是訴諸於使用「unsafePerformIO」之類的東西,除非這實際上是正確的時間來使用它(我懷疑)。

進一步信息:

我充滿數字和文件路徑文件,我已經分析此文件,並加載位於這些路徑的圖像轉換成一個列表[(智力,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) 

最後我用imageFromID與SDL.blitSurface繪製圖像,但我不能因爲IO 。

回答

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)只要你想得到你感興趣的表面。

+0

感謝MathematicalOrchid,這似乎確實是在正確的方向。我需要更改imageFromID函數,不是嗎? – user3638162

+0

@ user3638162是的,沒錯。你能解決它,還是需要提示? – MathematicalOrchid

+0

不幸的是,我需要一個提示。我知道該函數需要做的變成'imageFromID :: Int - > IO [(Int,SDL.Surface)] - > Maybe(SDL.Surface)''但我不知道如何寫這個。我需要爲此使用地圖嗎? – user3638162

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