Making unneeded conversions a no-op
ghc, haskell, image, optimization
Solution
I'd suggest that handle this the same way as GHC handles numeric conversions (e.g. `fromIntegral`), which is via rewrite rules.
If you look in GHC.Real, you find
-- | general coercion from integral types
fromIntegral :: (Integral a, Num b) => a -> b
fromIntegral = fromInteger . toInteger
{-# RULES
"fromIntegral/Int->Int" fromIntegral = id :: Int -> Int
#-}
The default is a lot of round-tripping for integral types, but fortunately that never happens because there are RULEs for all library-provided integral types.
There are many more RULEs specified in GHC.Int for example to handle the rest of the conversions. You'll find a similar setup for other similar functions (e.g. `realToFrac`).
Now there's one major problem with your use-case, which is that it's often difficult for RULEs to match on class methods. There are two ways around this. The first is to define a common type (e.g. `Integer` in GHC's code), and provide class methods to convert to and from that type. Then write a general-purpose conversion function (e.g. `fromIntegral`), use that everywhere, and have your RULEs match on it.
The other approach is to do something like this:
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 #-}
The former is what GHC does, so it's likely to work well. I've been using the latter approach recently and haven't had any issues though, so either one should work.
Problem
I'm writing a program which reads and writes images that supports multiple pixel types (i.e. RGB, CMYK, greyscale etc.). These pixel types can use different types of components, sort of like this: ``` 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 CUChar` or `getPixel myImage (10, 23) :: RGB CFloat` depending on the pixel format you want. The problem is that I don't know how to implement `fromComponent` in an efficient manner. Essentially, I would like unnecessary conversions such as `fromComponent (1 :: CUChar) :: CUChar` and `fromComponent (0.5 :: CFloat) :: CFloat` to be no-ops. I guessing that I'll have to rely on optimizations in any case. Note: This might not be a good design anyway so if someone has a better suggestion I'm open to this. I'd still like to know how to make this solution work.