跨类型类的模式匹配 [英] Pattern matching across type classes

查看:107
本文介绍了跨类型类的模式匹配的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是一名Haskell新手,所以很有可能我错过了一些明显的...



我想用ad hoc编写一个通用的颜色量化算法多态性。然而,我在使用模式匹配来获取数据方面遇到了一些麻烦(我实际上还没有进入量化位)。



我无法描述这个简洁的,所以这里是我的代码的简化版本,它展示了这个问题:

  { - #LANGUAGE FlexibleInstances# - } 

导入Data.Word

类型ColourGrey = Word8

data ColourRGB = ColourRGB Word8 Word8 Word8
派生(显示)

data ColourStream = Grays [ColourGrey]
|颜色[ColourRGB]
派生(显示)

类颜色a其中
extractStreamData :: ColourStream - > [a]

实例Color ColourGrey其中
extractStreamData(Grays x)= x

实例Color ColourRGB其中
extractStreamData(Colors x)= x

someColours =颜色[ColourRGB 255 0 0,ColourRGB 0 255 0,ColourRGB 0 0 255]
someGreys =灰色[0,127,255]

main: :IO()
main = do
print $ extractStreamData someColours
print $ extractStreamData someGreys

extractStreamData 的调用会失败,如下所示:

 没有使用`extractStreamData'引发的(Color a1)
的实例
类型变量`a1'不明确
可能的修正:添加修复这些类型变量的类型签名( s)
注意:有几个潜在的实例:
实例Color ColourRGB - 定义在test.hs:20:10
实例Color ColourGrey - 定义在test.hs:17:10
在`($)'的第二个参数中,即
`extractStreamDa ta someGreys'
在'do'块的标记中:print $ extractStreamData someGreys
在表达式中:
do {print $ extractStreamData(someColours :: ColourStream);
print $ extractStreamData someGreys}

对我而言,这意味着Haskell无法推断要使用哪个实例(颜色或灰度)。这是对的吗?如果是这样,我该如何解决这个问题?






nb c $ c> ColourGrey 和 ColourRGB 不在我的影响范围之内(它们是外部库的一部分)。所以任何建议都需要模仿这两种类型。我不想惹恼 ColourStream ,因为它在很多其他地方都有使用过。



我需要访问原始列表的原因是我可以使用诸如 map 等的东西。如果有一个巧妙的技巧,我还没有学习哪些将会使 ColourStream iterable,那么我想这可能会奏效...... < /> />

解决方案

问题是Haskell看到 extractStreamData 并意识到它将返回一些颜色a =>一个,但然后你管它进入显示,所以它也意识到 a 是一个 Show ,但之后没有提及 a



这意味着Haskell无法弄清楚哪种类型的 a 应该是。解决方案只是帮助typechecker并添加一些签名。

$ print $(extractStreamData someGreys :: [ColourGrey])

类似。



然而,你的类型类实例是有点...令人担忧。如果你通过了 ColourGray ColourRGB 实例,会发生什么?请注意,类型类只是一种基于类型的重载的方法。真的,它看起来像你想像丹尼尔瓦格纳有什么或类似的东西

  translateRGB :: ColourRGB  - > ColourGrey 
translateGrey :: ColourGrey - > ColourRGB

然后让您的实例更像是

 实例Color ColourGrey其中
extractStreamData(Grays x)= x
extractStreamData(Colors x)= map translateRGB x

这样您就可以选择是否将流视为 ColourGrey s或 ColourRGB s并使用它。现在,当您使用 extractStreamData 时,您并不是想先弄清楚流中的内容。


I'm a Haskell newbie, so chances are I've missed something obvious...

I am trying to write a generic colour quantisation algorithm using ad hoc polymorphism. However, I'm having some trouble getting my data out with pattern matching (I've not actually got to the quantisation bit, yet).

I can't describe this succinctly, so here's a simplified version of my code which exhibits the problem:

{-# LANGUAGE FlexibleInstances #-}

import Data.Word

type ColourGrey = Word8

data ColourRGB = ColourRGB Word8 Word8 Word8
  deriving (Show)

data ColourStream = Greys   [ColourGrey]
                  | Colours [ColourRGB]
                    deriving (Show)

class Colour a where
  extractStreamData :: ColourStream -> [a]

instance Colour ColourGrey where
  extractStreamData (Greys x) = x

instance Colour ColourRGB where
  extractStreamData (Colours x) = x

someColours = Colours [ColourRGB 255 0 0, ColourRGB 0 255 0, ColourRGB 0 0 255]
someGreys   = Greys   [0, 127, 255]

main :: IO ()
main = do
  print $ extractStreamData someColours
  print $ extractStreamData someGreys

The calls to extractStreamData fail with the following:

No instance for (Colour a1)
  arising from a use of `extractStreamData'
The type variable `a1' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Note: there are several potential instances:
  instance Colour ColourRGB -- Defined at test.hs:20:10
  instance Colour ColourGrey -- Defined at test.hs:17:10
In the second argument of `($)', namely
  `extractStreamData someGreys'
In a stmt of a 'do' block: print $ extractStreamData someGreys
In the expression:
  do { print $ extractStreamData (someColours :: ColourStream);
       print $ extractStreamData someGreys }

This implies, to me, that Haskell can't infer which instance to use (the one for colours or the one for greyscale). Would that be right? If so, how would I go about fixing this?


n.b. The definitions of ColourGrey and ColourRGB are outside my scope of influence (they're part of an external library). So any suggestions need to be modulo these two types. I'd prefer not to mess about with ColourStream, either, as it's used in lots of other places.

The reason I need to access the "raw" lists is so I can work with things like map, etc. If there's a neat trick I've yet to learn which will make ColourStream iterable, then I suppose that would work... </thinking aloud>

解决方案

The problem is that Haskell sees extractStreamData and realizes it's going to return some Colour a => a, but then you pipe that into show so it also realizes that a is an instance of Show, but after that there's no mention of a.

This means that Haskell can't figure out which type a should be. The solution is just to help out the typechecker and add some signatures

print $ (extractStreamData someGreys :: [ColourGrey])

like that.

However your typeclass instances are a bit... worrisome. What would happen if you passed you passed a ColourGray to the ColourRGB instance? Blowing up at runtime with little to know information is a bad response.

Remember that typeclasses is just a way of doing [really souped up] type based overloading. Really it looks like you want like what Daniel Wagner has or something like

translateRGB :: ColourRGB -> ColourGrey
translateGrey  :: ColourGrey -> ColourRGB

And then make your instances more like

instance Colour ColourGrey where
  extractStreamData (Greys x) = x
  extractStreamData (Colours x) = map translateRGB x

so that you just choose whether you want to treat your stream as ColourGreys or ColourRGBs and work with that. Now when you use extractStreamData you're not trying to figure out what's in the stream first.

这篇关于跨类型类的模式匹配的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆