Haskell,实例和类型之间的类型匹配问题 class
Haskell, problems matching types between an instance and a type class
我试图通过基于现有库 JuicyPixels.[=23 将整数列表转换为像素向量(具有相同的基础值但类型不同)来进行一些图像处理=]
但是当我试图让我的 pixel
成为图像时,发生了一个错误:像素的类型为 Pixel8
,它是类型 class [=16] 的一个实例=],但是ghci告诉我它不能匹配这些类型:
? Couldn't match type ‘px’ with ‘Pixel8’
‘px’ is a rigid type variable bound by
the type signature for:
makeListImg :: forall px.
Pixel px =>
Int -> Int -> [Int] -> Image px
at src\ImageHandling.hs:63:1-69
Expected type: T.MutableImage s Pixel8 -> ST s (Image px)
Actual type: T.MutableImage (PrimState (ST s)) px
-> ST s (Image px)
? In the second argument of ‘(>>=)’, namely ‘T.unsafeFreezeImage’
In the expression:
makeListMutableImg (w, h) (lst2px8 lst) >>= T.unsafeFreezeImage
In an equation for ‘img’:
img
= makeListMutableImg (w, h) (lst2px8 lst) >>= T.unsafeFreezeImage
? Relevant bindings include
img :: ST s (Image px) (bound at src\ImageHandling.hs:66:11)
makeListImg :: Int -> Int -> [Int] -> Image px
(bound at src\ImageHandling.hs:64:1)
|
66 | img = makeListMutableImg (w, h) (lst2px8 lst) >>= T.unsafeFreezeImage
| ^^^^^^^^^^^^^^^^^^^
我的代码是(从第 63 行开始):
makeListImg :: forall px. Pixel px => Int -> Int -> [Int] -> Image px
makeListImg w h lst = runST img
where img :: ST s (Image px)
img = makeListMutableImg (w, h) (lst2px8 lst) >>= T.unsafeFreezeImage
lst2px8 :: [Int] -> [Pixel8]
lst2px8 = map toPixel8
makeListMutableImg :: forall m px. (Pixel px, PrimMonad m) => (Int, Int) -> [px] -> m (T.MutableImage (PrimState m) px)
makeListMutableImg (w, h) lst = T.MutableImage w h `liftM` vec
where elemSize = T.componentCount (undefined :: px)
vec = do
arr <- M.new (w * h * elemSize)
let drawLineFromList :: Int -> Int -> [px] -> m ()
drawLineFromList _ y _ | y >= h = return ()
drawLineFromList idx y list = column idx 0 list
where column :: Int -> Int -> [px] -> m ()
column i x l | x >= w = drawLineFromList i (y+1) l
column i x l@(head:tail) = do
T.unsafeWritePixel arr i head
column (i+elemSize) (x+1) tail
drawLineFromList 0 0 lst
return arr
这些代码太多了,对此我真的很抱歉,但我对自己在做什么并不清楚;我只是遵循 library.
中的想法
函数中monad和抽象层太多了,真不知道应该关注哪里。我想将列表复制到 MutableImage
中的可变向量,然后使用 unsafeFreezeImage
和 runST
将其转换为 Image px
,但类型阻止了我。我现在该怎么办,我该如何解决这个问题?
我认为最好的方法是直接构建 Image
。这只是一个常规数据类型:
data Image a = Image { imageWidth :: !Int
, imageHeight :: !Int
, imageData :: Vector (PixelBaseComponent a) }
其中 Vector
来自 Data.Vector.Storable
.
对于 ImageRGB8
,PixelBaseComponent ImageRGB8
是 Word8
,而 Vector Word8
以行优先顺序排列,具有连续的每像素组件。从你的代码来看,这就是你的 [Int]
已经安排的方式,所以你的 makeListImg
函数应该像这样简单:
import Codec.Picture
import qualified Data.Vector.Storable as VS
makeListImg :: Int -> Int -> [Int] -> Image PixelRGB8
makeListImg w h = Image w h . VS.fromList . map fromIntegral
我无法想象 makeListImg
的多态版本会有用的应用程序,但可以定义如下内容:
unsafeMakeListImg :: (Integral (PixelBaseComponent p), VS.Storable (PixelBaseComponent p))
=> Int -> Int -> [Int] -> Image p
unsafeMakeListImg w h = Image w h . VS.fromList . map fromIntegral
这对于所有具有完整像素组件的图像格式来说已经足够通用了。尝试使用它的问题(以及我称之为“不安全”的原因)是 p
的推断类型将决定所提供列表 [Int]
结构的有效性。原始 makeListImg
也是不安全的,但至少它以可预测的方式不安全——你知道所需的 [Int]
参数始终是 Image PixelRGB8
.
的数据
一个独立的例子:
import Codec.Picture
import qualified Data.Vector.Storable as VS
makeListImg :: Int -> Int -> [Int] -> Image PixelRGB8
makeListImg w h = Image w h . VS.fromList . map fromIntegral
main = do
-- make a left-to-right red gradient
let foo = makeListImg 100 100 $ concat [[156+x,0,0] | x <- [0..99], y <- [0..99]]
saveJpgImage 75 "foo.jpg" $ ImageRGB8 foo
我试图通过基于现有库 JuicyPixels.[=23 将整数列表转换为像素向量(具有相同的基础值但类型不同)来进行一些图像处理=]
但是当我试图让我的 pixel
成为图像时,发生了一个错误:像素的类型为 Pixel8
,它是类型 class [=16] 的一个实例=],但是ghci告诉我它不能匹配这些类型:
? Couldn't match type ‘px’ with ‘Pixel8’
‘px’ is a rigid type variable bound by
the type signature for:
makeListImg :: forall px.
Pixel px =>
Int -> Int -> [Int] -> Image px
at src\ImageHandling.hs:63:1-69
Expected type: T.MutableImage s Pixel8 -> ST s (Image px)
Actual type: T.MutableImage (PrimState (ST s)) px
-> ST s (Image px)
? In the second argument of ‘(>>=)’, namely ‘T.unsafeFreezeImage’
In the expression:
makeListMutableImg (w, h) (lst2px8 lst) >>= T.unsafeFreezeImage
In an equation for ‘img’:
img
= makeListMutableImg (w, h) (lst2px8 lst) >>= T.unsafeFreezeImage
? Relevant bindings include
img :: ST s (Image px) (bound at src\ImageHandling.hs:66:11)
makeListImg :: Int -> Int -> [Int] -> Image px
(bound at src\ImageHandling.hs:64:1)
|
66 | img = makeListMutableImg (w, h) (lst2px8 lst) >>= T.unsafeFreezeImage
| ^^^^^^^^^^^^^^^^^^^
我的代码是(从第 63 行开始):
makeListImg :: forall px. Pixel px => Int -> Int -> [Int] -> Image px
makeListImg w h lst = runST img
where img :: ST s (Image px)
img = makeListMutableImg (w, h) (lst2px8 lst) >>= T.unsafeFreezeImage
lst2px8 :: [Int] -> [Pixel8]
lst2px8 = map toPixel8
makeListMutableImg :: forall m px. (Pixel px, PrimMonad m) => (Int, Int) -> [px] -> m (T.MutableImage (PrimState m) px)
makeListMutableImg (w, h) lst = T.MutableImage w h `liftM` vec
where elemSize = T.componentCount (undefined :: px)
vec = do
arr <- M.new (w * h * elemSize)
let drawLineFromList :: Int -> Int -> [px] -> m ()
drawLineFromList _ y _ | y >= h = return ()
drawLineFromList idx y list = column idx 0 list
where column :: Int -> Int -> [px] -> m ()
column i x l | x >= w = drawLineFromList i (y+1) l
column i x l@(head:tail) = do
T.unsafeWritePixel arr i head
column (i+elemSize) (x+1) tail
drawLineFromList 0 0 lst
return arr
这些代码太多了,对此我真的很抱歉,但我对自己在做什么并不清楚;我只是遵循 library.
中的想法函数中monad和抽象层太多了,真不知道应该关注哪里。我想将列表复制到 MutableImage
中的可变向量,然后使用 unsafeFreezeImage
和 runST
将其转换为 Image px
,但类型阻止了我。我现在该怎么办,我该如何解决这个问题?
我认为最好的方法是直接构建 Image
。这只是一个常规数据类型:
data Image a = Image { imageWidth :: !Int
, imageHeight :: !Int
, imageData :: Vector (PixelBaseComponent a) }
其中 Vector
来自 Data.Vector.Storable
.
对于 ImageRGB8
,PixelBaseComponent ImageRGB8
是 Word8
,而 Vector Word8
以行优先顺序排列,具有连续的每像素组件。从你的代码来看,这就是你的 [Int]
已经安排的方式,所以你的 makeListImg
函数应该像这样简单:
import Codec.Picture
import qualified Data.Vector.Storable as VS
makeListImg :: Int -> Int -> [Int] -> Image PixelRGB8
makeListImg w h = Image w h . VS.fromList . map fromIntegral
我无法想象 makeListImg
的多态版本会有用的应用程序,但可以定义如下内容:
unsafeMakeListImg :: (Integral (PixelBaseComponent p), VS.Storable (PixelBaseComponent p))
=> Int -> Int -> [Int] -> Image p
unsafeMakeListImg w h = Image w h . VS.fromList . map fromIntegral
这对于所有具有完整像素组件的图像格式来说已经足够通用了。尝试使用它的问题(以及我称之为“不安全”的原因)是 p
的推断类型将决定所提供列表 [Int]
结构的有效性。原始 makeListImg
也是不安全的,但至少它以可预测的方式不安全——你知道所需的 [Int]
参数始终是 Image PixelRGB8
.
一个独立的例子:
import Codec.Picture
import qualified Data.Vector.Storable as VS
makeListImg :: Int -> Int -> [Int] -> Image PixelRGB8
makeListImg w h = Image w h . VS.fromList . map fromIntegral
main = do
-- make a left-to-right red gradient
let foo = makeListImg 100 100 $ concat [[156+x,0,0] | x <- [0..99], y <- [0..99]]
saveJpgImage 75 "foo.jpg" $ ImageRGB8 foo