1

I am very new to Haskell and do not have good understanding of monads for now. I am using gloss for making chess. The issue I am facing is in the loading of multiple images. I am using loadBMP function provided by haskell to load image. Its signature is:

loadBMP :: FilePath -> IO Picture

I can load single image but can't load array of images.

-- This function calculates the path of all the images and then apply loadBMP function on it.

loadPieceImages :: [IO Picture]
loadPieceImages = do
  map (loadBMP . (\n -> "images/" ++ n ++ ".bmp") . (\n -> if n < 6 then show n ++ "-w" else show (n `mod` 6) ++ "-b")) [0 .. 12]

main :: IO ()
main = do
  images <- loadPieceImages  -- On this line I am getting error.
  play window (makeColor 1 0 0 1) 30 initialState draw transform (const id)

The main issue is that I have [IO Picture] type but I don't how will be turn it into [Picture].

This thing might be very basic but I can't understand monads for now. So kindly explain the answer you give.

Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
Maheer Ali
  • 35,834
  • 5
  • 42
  • 73

1 Answers1

1

Since you've (correctly) declared main as IO (), the do notation and the <- arrow enables you to 'peel off' the IO wrapper. Thus, when you write images <- loadPieceImages, the compiler expects loadPieceImages to have an IO type. loadPieceImages, however, has the type [IO Picture], which is why the compiler complains. The outermost wrapper is [], not IO.

If, on the other hand, you had a IO [Picture] value, you'd be able to use the <- arrow to peel of the IO wrapper to 'get at' the [Picture] list inside it.

In other words, you need a function with the type [IO Picture] -> IO [Picture]. You can Hoogle that type and consider the suggestions.

Once you get the hang of it, you'll start to notice that whenever you want to 'flip' the 'stacking' of two wrappers (like IO and []), there's a general-purpose function for that: sequence. This function takes a list of any Monad m and flips it to m [a]. Since IO is a Monad instance, that'll work here as well.

So, something like

images <- sequence loadPieceImages

should work (I haven't actually tried to compile this, since the OP isn't a minimal reproducible example, so it's possible you'll have to tweak this a bit, but that's the general idea: use sequence).

Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
  • 1
    I'd say probably the right fix is rather to change the `map` in the definition of `loadPieceImages` to `mapM` (and fix the type signature accordingly). – Daniel Wagner Dec 06 '21 at 21:14