Как мне написать пиксели с помощью JuicyPixels? (в монаде ST)
Я хотел бы записать несколько пикселей в изображение и записать изображение на диск. Я следовал совету, который слышал от многих Хаскеллеров, чтобы они следили за сигнатурами типов и, по сути, играли в "типичные тетрисы" до тех пор, пока я не пойду туда, куда иду. В основном это работает для меня, но я сталкиваюсь с некоторыми проблемами.
Чтобы написать пиксель, есть функция:
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, чтобы я мог написать в него? И что еще более важно, как я могу закрепиться на типах внутри этой монады, чтобы я мог решить эту проблему для себя?
1 ответ
Вы сделали это в принципе правильно, вы просто перепутали позиции аргументов:
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
должен быть в первой позиции аргументации.