Creating unnecessary no-op conversions

I am writing a program that reads and writes images that support several types of pixels (e.g. RGB, CMYK, grayscale, etc.). These types of pixels can use different types of components, for example:

class (Storable c) => PixelComponent c where
    blackWhite :: c -> (c, c)
    toInt :: c -> Int
    toRealFrac :: (RealFrac a) => c -> a
    fromComponent :: (PixelComponent a) => a -> c

instance PixelComponent CUChar where
    blackWhite x = (minBound x, maxBound x)
    toInt = id
    toRealFrac = fromIntegral
    fromComponent x = ???

instance PixelComponent CFloat where
    black = 0.0
    white = 1.0
    toInt = truncate
    toReal = id
    fromComponent x = ???

class (Storable pix) => Pixel pix where
    red :: pix c -> c
    green :: pix c -> c
    blue :: pix c -> c
    alpha :: pix c -> c
    luminance :: pix c -> c
    fromPixel :: (Pixel a) => a c -> pix c

The idea is that you should be able to do getPixel myImage (10, 23) :: RGB CUChareither getPixel myImage (10, 23) :: RGB CFloatdepending on the pixel format you want. The problem is that I do not know how to implement it effectively fromComponent. Essentially, I would like unnecessary conversions such as fromComponent (1 :: CUChar) :: CUCharand fromComponent (0.5 :: CFloat) :: CFloatto be non-ops. I assume that in any case I will have to rely on optimization.

. , , - , . , .

+3
2

, GHC (, fromIntegral), .

GHC.Real,

-- | general coercion from integral types
fromIntegral :: (Integral a, Num b) => a -> b
fromIntegral = fromInteger . toInteger

{-# RULES
"fromIntegral/Int->Int" fromIntegral = id :: Int -> Int
    #-}

, , , , , .

, GHC.Int, , . (, realToFrac).

, . . - (, Integer GHC) . (, fromIntegral), , .

- - :

instance PixelComponent CUChar where
    blackWhite x = (minBound x, maxBound x)
    toInt = id
    toRealFrac = fromIntegral
    {-# INLINE fromComponent #-}
    fromComponent = toCUChar

toCUChar :: PixelComponent a => a -> CUChar
toCUChar = ...

{-# RULES "fromComponent/CUChar->CUChar" toCUChar = id :: CUChar -> CUChar #-}

- , GHC, , , . , .

+6

, , n^2 .

, , , . , - . .

(ideone):

{-# LANGUAGE MultiParamTypeClasses #-}

import Data.Char (toUpper, toLower)

data Lower = Lower String deriving Show
data Mixed = Mixed String deriving Show
data Upper = Upper String deriving Show

toUpperStr = map toUpper
toLowerStr = map toLower

class Make a where
  make :: String -> a

instance Make Lower where
  make s = Lower (toLowerStr s)

instance Make Mixed where
  make s = Mixed s

instance Make Upper where
  make s = Upper (toUpperStr s)

class Convert a b where
  convert :: a -> b

instance Convert Lower Lower where
  convert = id

instance Convert Lower Mixed where
  convert (Lower s) = Mixed s

instance Convert Lower Upper where
  convert (Lower s) = Upper (toUpperStr s)

instance Convert Mixed Lower where
  convert (Mixed s) = Lower (toLowerStr s)

instance Convert Mixed Mixed where
  convert = id

instance Convert Mixed Upper where
  convert (Mixed s) = Upper (toUpperStr s)

instance Convert Upper Lower where
  convert (Upper s) = Lower (toLowerStr s)

instance Convert Upper Mixed where
  convert (Upper s) = Mixed s

instance Convert Upper Upper where
  convert = id

main = print (convert ((make "Hello World") :: Lower) :: Upper)
0

All Articles