Haskell Generic Representation
A generic representation is built from a few named pieces. M1 wraps metadata, K1 holds one field, the product piece joins fields side by side, and the sum piece marks a choice between constructors.
One field counts as one
M1 wrappers lead to one K1 field. The count proves the shape has one field.
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
import GHC.Generics
data Box a = Box a deriving (Show, Eq, Generic)
class GCount f where
gcount :: f p -> Int
instance GCount (K1 i c) where
gcount _ = 1
instance GCount f => GCount (M1 i c f) where
gcount (M1 x) = gcount x
instance (GCount f, GCount g) => GCount (f :*: g) where
gcount (x :*: y) = gcount x + gcount y
instance GCount U1 where
gcount _ = 0
genericCount :: (Generic a, GCount (Rep a)) => a -> Int
genericCount x = gcount (from x)
main :: IO ()
main = print (genericCount (Box 5))Two fields count as two
The product piece joins two field pieces. The count proves the shape has two fields.
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
import GHC.Generics
data Pair a b = Pair a b deriving (Show, Eq, Generic)
class GCount f where
gcount :: f p -> Int
instance GCount (K1 i c) where
gcount _ = 1
instance GCount f => GCount (M1 i c f) where
gcount (M1 x) = gcount x
instance (GCount f, GCount g) => GCount (f :*: g) where
gcount (x :*: y) = gcount x + gcount y
instance GCount U1 where
gcount _ = 0
genericCount :: (Generic a, GCount (Rep a)) => a -> Int
genericCount x = gcount (from x)
main :: IO ()
main = print (genericCount (Pair 3 "hi"))Three fields count as three
Two product joins hold three field pieces. The count proves the shape has three fields.
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
import GHC.Generics
data Triple a b c = Triple a b c deriving (Show, Eq, Generic)
class GCount f where
gcount :: f p -> Int
instance GCount (K1 i c) where
gcount _ = 1
instance GCount f => GCount (M1 i c f) where
gcount (M1 x) = gcount x
instance (GCount f, GCount g) => GCount (f :*: g) where
gcount (x :*: y) = gcount x + gcount y
instance GCount U1 where
gcount _ = 0
genericCount :: (Generic a, GCount (Rep a)) => a -> Int
genericCount x = gcount (from x)
main :: IO ()
main = print (genericCount (Triple 1 2 3))Example
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
import GHC.Generics
data Box a = Box a deriving (Show, Eq, Generic)
data Triple a b c = Triple a b c deriving (Show, Eq, Generic)
class GCount f where
gcount :: f p -> Int
instance GCount (K1 i c) where
gcount _ = 1
instance GCount f => GCount (M1 i c f) where
gcount (M1 x) = gcount x
instance (GCount f, GCount g) => GCount (f :*: g) where
gcount (x :*: y) = gcount x + gcount y
instance GCount U1 where
gcount _ = 0
genericCount :: (Generic a, GCount (Rep a)) => a -> Int
genericCount x = gcount (from x)
main :: IO ()
main = do print (genericCount (Box 5)); print (genericCount (Triple 1 2 3))Key points
- M1: the wrapper piece that carries metadata around another piece.
- K1: the piece that holds a single field value.
- Product: the piece that joins two pieces side by side.
- Sum: the piece that marks a choice between constructors.
- Generic function: a function that handles each piece once and works for many types.
In this example, the class handles each representation piece once, genericCount reads each value through from, and the two prints show one field for Box and three fields for Triple.
Note
representation pieces are named in prose here, and their values are never printed.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Haskell Playground
Exercise
Which piece holds a single field value?