MaiaVictor
MaiaVictor

Reputation: 53077

How to create ListIsomorphic instances for tuples and packed types?

Sorry, this is yet another topic in the same serie. I have a typeclass for things that are isomorphic to lists:

class ListIsomorphic l where
    type Elem l a :: Constraint
    type Elem l a = ()

    toList    :: l a -> [a]
    fromList  :: [a] -> l a

There are two cases for which I'm not managing to create an instance; singly-typed tuples and types that pack multiple elements in a single value.

type Tuple2 a   = (a,a)
newtype Pixel a = Pixel a

On this case, Pixel usually holds a Word32 with 4 elements that are extracted with bitwise operations:

red (Pixel pixel)   = pixel .&. 0x000000FF
green (Pixel pixel) = shiftR (pixel .&. 0x0000FF00) 8
blue (Pixel pixel)  = shiftR (pixel .&. 0x00FF0000) 16
alpha (Pixel pixel) = shiftR (pixel .&. 0xFF000000) 24

While both cases aren't isomorphic to lists (they are fixed length), having an instance would be useful, yet I'm not sure how to justify this to the type system. Writing an instance for tuples:

type Tuple2 a = (a,a)
instance ListIsomorphic Tuple2 where
    fromList [a,b] = (a,b)
    toList   (a,b) = [a,b]

I get:

Type synonym ‘Tuple2’ should have 1 argument, but has been given none

Writing an instance for Pixel:

instance ListIsomorphic Pixel where
    type Elem Pixel_ a = Word32
    fromList [r,g,b,a] = rgba r g b a
    toList pixel       = [red pixel, green pixel, blue pixel, alpha pixel]

I get:

Expected a constraint, but ‘Word32’ has kind ‘*’

Of course, I didn't expect that to work, but that is to say I have no idea how to write it.

Upvotes: 1

Views: 54

Answers (1)

leftaroundabout
leftaroundabout

Reputation: 120751

The constraint family

type Elem l a :: Constraint
type Elem l a = ()

allows you to restrict the types that may be contained in those containers. In the case of Tuple2, or lists themselves, this isn't necessary at all, because these can contain any type of element.
In the case e.g. of Storable vectors, you need primitive types that can actually be stored in a C array.
In the case of Pixel, you can only store one single type, namely Word32. That means you need an equational constraint:

instance ListIsomorphic Pixel where
    type Elem Pixel a = a~Word32

Upvotes: 3

Related Questions