I'd like to write some pixels into an image, and write the image to disk. I've been following the advice I've heard from many Haskellers to follow the type signatures, and essentially play "type tetris" until I get where I'm going. Its mostly working for me, but I'm running into some trouble.
To write a pixel, there's a function:
writePixel :: PrimMonad m => MutableImage (PrimState m) a -> Int -> Int -> a -> m ()
I can tell from reading the signature that I need to pass it a MutableImage, so I look for a function that with a MutableImage:
createMutableImage :: (PrimMonad m, Pixel px) => Int -> Int -> px -> m (MutableImage (PrimState m) px)
this seems to run inside some kind of state monad.
writeIt = runST $ createMutableImage 100 100 (100::Pixel8) >>=
freezeImage
This works, and returns nice grey image I can write to disk. But I have no idea how to get a hold of the MutableImage so I can write pixels to it! Simply interposing the writePixel call gives me an error I can't quite make out:
writeIt = runST $ createMutableImage 100 100 (100::Pixel8) >>=
writePixel 100 100 255 >>=
freezeImage
Results in:
Couldn't match type `MutableImage (PrimState (GHC.ST.ST s)) px0'
with `()'
Expected type: () -> GHC.ST.ST s (Image px0)
Actual type: MutableImage (PrimState (GHC.ST.ST s)) px0
-> GHC.ST.ST s (Image px0)
In the second argument of `(>>=)', namely `freezeImage'
In the second argument of `($)', namely
`createMutableImage 100 100 (100 :: Pixel8)
>>= writePixel 100 100 255
>>= freezeImage'
In the expression:
runST
$ createMutableImage 100 100 (100 :: Pixel8)
>>= writePixel 100 100 255
>>= freezeImage
I can tell from the writePixel signature that I'm missing the first argument for writePixel. How do I get a reference to the MutableImage so I can write to it? And more importantly, how do I get a foothold on the types inside this monad so I can work this stuff out for myself?
You have done it basically correctly, you just mixed up the positions of the arguements:
writeIt = runST $ do
pic <- createMutableImage 100 100 (100::Pixel8)
writePixel pic 100 100 255
freezeImage pic
Or if you don't like do
notation:
writeIt = runST $
createMutableImage 100 100 (100::Pixel8) >>=
\pic -> writePixel pic 100 100 255 >>=
\nothing -> freezeImage pic
What you had written would be equivalent to
writeIt = runST $ createMutableImage 100 100 (100::Pixel8) >>=
\pic -> writePixel 100 100 255 pic >>=
\nothing -> freezeImage nothing
but this is completely wrong, since nothing
has type ()
and pic
should be in the first arguement position.