3

我想将一些像素写入图像,并将图像写入磁盘。我一直在遵循我从许多 Haskeller 那里听到的建议来遵循类型签名,并且基本上玩“类型俄罗斯方块”,直到我到达我要去的地方。它主要为我工作,但我遇到了一些麻烦。

要写一个像素,有一个函数:

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)

这似乎在某种状态单子中运行。

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 中的类型上找到立足点,以便我自己解决这些问题?

4

1 回答 1

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应该处于第一个争论的位置。

于 2014-03-23T18:42:42.597 回答