Как мне написать пиксели с помощью 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 должен быть в первой позиции аргументации.

Другие вопросы по тегам