我想在图像中写入一些像素,然后将图像写入磁盘。 我一直在遵循我从许多Haskeller那里听到的关于类型签名的建议,并且基本上玩#34;类型俄罗斯方块"直到我到达我要去的地方。它主要为我工作,但我遇到了一些麻烦。
要写一个像素,有一个功能:
writePixel :: PrimMonad m => MutableImage (PrimState m) a -> Int -> Int -> a -> m ()
我可以通过阅读签名告诉我需要传递一个MutableImage,所以我寻找一个带有MutableImage的函数:
createMutableImage :: (PrimMonad m, Pixel px) => Int -> Int -> px -> m (MutableImage (PrimState m) px)
这似乎在某种状态monad中运行。
writeIt = runST $ createMutableImage 100 100 (100::Pixel8) >>=
freezeImage
这个工作,并返回我可以写入磁盘的漂亮的灰色图像。但我不知道如何获取MutableImage,所以我可以写像素!简单地插入writePixel调用就会给我一个错误,我无法理解:
writeIt = runST $ createMutableImage 100 100 (100::Pixel8) >>=
writePixel 100 100 255 >>=
freezeImage
结果:
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
我可以从writePixel签名中看出我错过了writePixel的第一个参数。我如何获得MutableImage的引用,以便我可以写入它?更重要的是,我如何在这个monad中的类型上站稳脚跟,这样我才能为自己解决这些问题?
答案 0 :(得分:5)
你已经基本上正确地完成了它,你只是混淆了争论的位置:
writeIt = runST $ do
pic <- createMutableImage 100 100 (100::Pixel8)
writePixel pic 100 100 255
freezeImage pic
或者,如果您不喜欢do
符号:
writeIt = runST $
createMutableImage 100 100 (100::Pixel8) >>=
\pic -> writePixel pic 100 100 255 >>=
\nothing -> freezeImage pic
你所写的内容相当于
writeIt = runST $ createMutableImage 100 100 (100::Pixel8) >>=
\pic -> writePixel 100 100 255 pic >>=
\nothing -> freezeImage nothing
但这是完全错误的,因为nothing
类型()
且pic
应位于第一个争论位置。