如何用JuicyPixels写像素? (在ST monad)

时间:2014-03-23 18:00:52

标签: haskell state-monad juicy-pixels

我想在图像中写入一些像素,然后将图像写入磁盘。 我一直在遵循我从许多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中的类型上站稳脚跟,这样我才能为自己解决这些问题?

1 个答案:

答案 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应位于第一个争论位置。