2

私は Haskell の初心者なので、明らかな何かを見落としている可能性があります...

アドホック ポリモーフィズムを使用して一般的な色の量子化アルゴリズムを作成しようとしています。ただし、パターン マッチングでデータを取得するのに問題があります (実際にはまだ量子化ビットに到達していません)。

これを簡潔に説明することはできないため、問題を示すコードの簡略版を次に示します。

{-# 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

呼び出しextractStreamDataは次のように失敗します。

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 }

これは、Haskell がどのインスタンスを使用するか (カラー用またはグレースケール用) を推測できないことを意味します。それは正しいでしょうか?もしそうなら、どうすればこれを修正できますか?


nbとの定義はColourGreyColourRGB私の影響範囲外です (それらは外部ライブラリの一部です)。したがって、提案はこれら 2 つのタイプを法とする必要があります。他の多くの場所で使用されているため、私も をいじりたくありませんColourStream

「生の」リストにアクセスする必要があるのは、 などを操作できるようにするためmapです。まだ習得していない反復可能にする巧妙なトリックがある場合はColourStream、それがうまくいくと思います...</thinking aloud>

4

3 に答える 3

4

問題は、Haskell がextractStreamDataいくつかの を返すことをColour a => a認識して認識することですが、それを show にパイプすると、それaが のインスタンスであることも認識されますがShow、その後は について言及されていませんa

これは、Haskell がどの型aであるべきか判断できないことを意味します。解決策は、タイプチェッカーを支援し、いくつかの署名を追加することです

print $ (extractStreamData someGreys :: [ColourGrey])

そのように。

ただし、型クラスのインスタンスは少し...気になります。ColourGrayインスタンスに aを渡した場合はどうなりColourRGBますか? 情報をほとんど知らずに実行時に爆破するのは、悪い反応です。

typeclasses は、型ベースのオーバーロードを [本当に強化した] 方法に過ぎないことを思い出してください。本当に、ダニエル・ワグナーが持っているようなものを望んでいるように見えます

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

そして、インスタンスをより似たものにします

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

ColourGreyストリームをs またはsとして扱うかどうかを選択して、それを操作するだけですColourRGB。を使用extractStreamDataすると、最初にストリームに何があるかを把握しようとはしません。

于 2013-10-31T16:54:51.007 に答える
1

確かではありませんが、あなたが本当に欲しいのは次のようなものだと思います:

onColourStream ::
    ([ColourGrey] -> [ColourGrey]) ->
    ([ColourRGB ] -> [ColourRGB ]) ->
    (ColourStream -> ColourStream)
onColourStream onGreys onRGBs (Greys gs) = Greys (onGreys gs)
onColourStream onGreys onRGBs (Colours rgbs) = Colours (onRGBs rgbs)

ColourGreyいくつかの操作 (軽量化操作など)をColourRGB共有し、それらの操作を自分が持っているものに使用したい場合は、型クラスを作成して次のようにすることができます

class Colour a where lighten :: Double -> a -> a
instance Colour ColourRGB  where lighten = ...
instance Colour ColourGrey where lighten = ...

onColourStreamPoly ::
    (forall a. Colour a => [a] -> [a]) ->
    (ColourStream -> ColourStream)
onColourStreamPoly f = onColourStream f f

onColourStreamPoly (map (lighten 0.5))次に、すべての色を半分に明るくするようなものを書くことができるかもしれません.

編集:「私が最終的にやりたいのは、画像の色データのストリーム(RGBまたはグレー)をパレット(常に画像の色空間に一致する別のストリーム)に一致させることです」に対応するには:その場合、私は思う最も簡単な方法は、単純にパターン マッチングを使用することです。次のような関数があるとします。

matchPalette :: Eq a => [a] -> [a] -> [Int]
myAlgorithm  :: [Int] -> [Int]
unmatchPalette :: [Int] -> [a] -> [a]

次に、次のようなことができます。

pipeline :: Eq a => [a] -> [a] -> [a]
pipeline xs ys = unmatchPalette (myAlgorithm (matchPalette xs ys)) xs

wholeShebang :: ColourStream -> ColourStream -> ColourStream
wholeShebang (Greys gs) (Greys gs') = Greys (pipeline gs gs')
wholeShebang (Colours rgbs) (Colours rgbs') = Colours (pipeline rgbs rgbs')
wholeShebang _ _ = error "Yikes! The colour stream and palette didn't match up."
于 2013-10-31T17:17:49.330 に答える
0

これは、コンパイルの問題を除いた、プログラムのより単純なバージョンです。

import Data.Word

type ColourGrey = Word8

data ColourRGB = ColourRGB Word8 Word8 Word8
  deriving (Show)

data ColourStream a = ColourStream [a]

extractStreamData (ColourStream stream) = stream

someColours = ColourStream [ColourRGB 255 0 0, ColourRGB 0 255 0, ColourRGB 0 0 255]
someGreys   = ColourStream ([0, 127, 255] :: [ColourGrey])

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

もちろん、この単純な例以外でこれらの定義をどのように使用するかはわかりません。そのため、あなたがやろうとしていることに対して十分であるかどうかはわかりません.

于 2013-10-31T17:27:04.353 に答える