Haskell多态解构

4

我开始使用Juicy Pixels库,但在解构时遇到了一些问题。

有以下类型:

data DynamicImage =
    ImageY8   (Image Pixel8)
    | ImageYA8  (Image PixelYA8)
    | ImageRGB8 (Image PixelRGB8)
    | ImageRGBA8 (Image PixelRGBA8) 
    | ImageYCbCr8 (Image PixelYCbCr8)

Pixel*是一个Pixel类的实例集合。

有一些函数适用于Image a类型,我希望从DynamicImage中提取Image a,但我却无法做到。

当我尝试做像这样的事情时

img :: (Pixel a) => DynamicImage -> Image a
img (ImageY8 i) = i
img (ImageYA8 i) = i  
img (ImageRGB8 i) = i
img (ImageRGBA8 i) = i  
img (ImageYCbCr8 i) = i

解释器会抛出错误,例如:
Couldn't match type `PixelYCbCr8' with `GHC.Word.Word8'
Expected type: Image b
  Actual type: Image Pixel8
In the expression: i
In an equation for `img': img (ImageY8 i) = i

有没有其他方法可以提取图像a的数据?
1个回答

5

你的方法不适用,因为img的类型签名承诺为每个a提供一个图像,而不仅仅是由img本身选择的某个特定的。

一种可能性是改变类型签名,同时也要采取处理多态图像的函数,并使用RankNTypes来允许这样做:

withImg :: DynamicImage -> (forall a. Pixel a => Image a -> b) -> b
withImg (ImageY8 i) f = f i
withImg (ImageYA8 i) f = f i  
withImg (ImageRGB8 i) f = f i
withImg (ImageRGBA8 i) f = f i  
withImg (ImageYCbCr8 i) f = f i

这可确保传递给 withImg 的函数将接受任何 Image 作为参数,无需进一步的信息。


3
这实际上是将 存在 a. Pixel a => DynamicImage -> Image a 转换成延续传递风格。 - Ptharien's Flame
是的,但那不是有效的 Haskell 类型。在 Haskell 中是否有一种非 CPS 变体可用? - Joachim Breitner
data SomeImage = forall a. Pixel a => SomeImage (Image a)(需要 -XExistentialQuantification)。 - Vitus
此外,它是**(a)** DynamicImage -> (exists a. Pixel a => Image a)的转换 - 请注意exists的位置。**(b)** exists a. Pixel a => DynamicImage -> Image a在某种意义上比较强大,因为你可以从ba,但反过来不行。 - Vitus
好的,你可以引入一个新类型。但是要实际使用原始问题中提到的函数,这些函数需要一个“Pixel a”而不是一个SomeImage,你必须再次进行CPS转换。 - Joachim Breitner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接