{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveFoldable #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# OPTIONS_HADDOCK not-home #-} {- | Most users of this library do not need this module. The functions here are used to build functions that apply a 'Colonnade' to a collection of values, building a table from them. Ultimately, a function that applies a @Colonnade Headed MyCell a@ to data will have roughly the following type: > myTableRenderer :: Foldable g => Colonnade Headed MyCell a -> g a -> MyContent In the companion packages @yesod-colonnade@ and @reflex-dom-colonnade@, functions with similar type signatures are readily available. These packages use the functions provided here in the implementations of their rendering functions. It is recommended that users who believe they may need this module look at the source of the companion packages to see an example of how this module\'s functions are used. Other backends are encouraged to use these functions to build monadic or monoidal content from a 'Colonnade'. The functions exported here take a 'Colonnade' and convert it to a fragment of content. The functions whose names start with @row@ take at least a @Colonnade f c a@ and an @a@ value to generate a row of content. The functions whose names start with @header@ need the @Colonnade f c a@ but not an @a@ value since a value is not needed to build a header. -} module Colonnade.Encode ( -- * Colonnade -- ** Types Colonnade (..) , OneColonnade (..) , Headed (..) , Headless (..) , Sized (..) , ExtractForall (..) -- ** Typeclasses , Headedness (..) -- ** Row , row , rowMonadic , rowMonadic_ , rowMonadicWith , rowMonoidal , rowMonoidalHeader -- ** Header , header , headerMonadic , headerMonadic_ , headerMonadicGeneral , headerMonadicGeneral_ , headerMonoidalGeneral , headerMonoidalFull -- ** Other , bothMonadic_ , sizeColumns -- * Cornice -- ** Types , Cornice (..) , AnnotatedCornice (..) , OneCornice (..) , Pillar (..) , ToEmptyCornice (..) , Fascia (..) -- ** Encoding , annotate , annotateFinely , size , endow , discard , headersMonoidal , uncapAnnotated ) where import Control.Monad.ST (ST, runST) import Data.Foldable import Data.Functor.Contravariant (Contravariant (..)) import Data.List.NonEmpty (NonEmpty ((:|))) import Data.Profunctor (Profunctor (..)) import Data.Vector (Vector) import qualified Data.Semigroup as Semigroup import qualified Data.Vector as V import qualified Data.Vector as Vector import qualified Data.Vector.Generic as GV import qualified Data.Vector.Unboxed as VU import qualified Data.Vector.Unboxed.Mutable as MVU {- | Consider providing a variant the produces a list instead. It may allow more things to get inlined in to a loop. -} row :: (c1 -> c2) -> Colonnade f a c1 -> a -> Vector c2 row g (Colonnade v) a = flip Vector.map v $ \(OneColonnade _ encode) -> g (encode a) bothMonadic_ :: (Monad m) => Colonnade Headed a c -> (c -> c -> m b) -> a -> m () bothMonadic_ (Colonnade v) g a = forM_ v $ \(OneColonnade (Headed h) encode) -> g h (encode a) rowMonadic :: (Monad m, Monoid b) => Colonnade f a c -> (c -> m b) -> a -> m b rowMonadic (Colonnade v) g a = flip foldlMapM v $ \e -> g (oneColonnadeEncode e a) rowMonadic_ :: (Monad m) => Colonnade f a c -> (c -> m b) -> a -> m () rowMonadic_ (Colonnade v) g a = forM_ v $ \e -> g (oneColonnadeEncode e a) rowMonoidal :: (Monoid m) => Colonnade h a c -> (c -> m) -> a -> m rowMonoidal (Colonnade v) g a = foldMap (\(OneColonnade _ encode) -> g (encode a)) v rowMonoidalHeader :: (Monoid m) => Colonnade h a c -> (h c -> c -> m) -> a -> m rowMonoidalHeader (Colonnade v) g a = foldMap (\(OneColonnade h encode) -> g h (encode a)) v rowUpdateSize :: -- | Get size from content (c -> Int) -> MutableSizedColonnade s h a c -> a -> ST s () rowUpdateSize toSize (MutableSizedColonnade v mv) a = if MVU.length mv /= V.length v then error "rowMonoidalSize: vector sizes mismatched" else V.imapM_ ( \ix (OneColonnade _ encode) -> MVU.modify mv (\oldSize -> max oldSize (toSize (encode a))) ix ) v headerUpdateSize :: (Foldable h) => -- | Get size from content (c -> Int) -> MutableSizedColonnade s h a c -> ST s () headerUpdateSize toSize (MutableSizedColonnade v mv) = if MVU.length mv /= V.length v then error "rowMonoidalSize: vector sizes mismatched" else V.imapM_ ( \ix (OneColonnade h _) -> MVU.modify mv (\oldSize -> max oldSize (foldl' (\sz c -> max sz (toSize c)) 0 h)) ix ) v sizeColumns :: (Foldable f, Foldable h) => -- | Get size from content (c -> Int) -> f a -> Colonnade h a c -> Colonnade (Sized (Maybe Int) h) a c sizeColumns toSize rows colonnade = runST $ do mcol <- newMutableSizedColonnade colonnade headerUpdateSize toSize mcol mapM_ (rowUpdateSize toSize mcol) rows freezeMutableSizedColonnade mcol newMutableSizedColonnade :: Colonnade h a c -> ST s (MutableSizedColonnade s h a c) newMutableSizedColonnade (Colonnade v) = do mv <- MVU.replicate (V.length v) 0 return (MutableSizedColonnade v mv) freezeMutableSizedColonnade :: MutableSizedColonnade s h a c -> ST s (Colonnade (Sized (Maybe Int) h) a c) freezeMutableSizedColonnade (MutableSizedColonnade v mv) = if MVU.length mv /= V.length v then error "rowMonoidalSize: vector sizes mismatched" else do sizeVec <- VU.freeze mv return $ Colonnade $ V.map (\(OneColonnade h enc, sz) -> OneColonnade (Sized (Just sz) h) enc) $ V.zip v (GV.convert sizeVec) rowMonadicWith :: (Monad m) => b -> (b -> b -> b) -> Colonnade f a c -> (c -> m b) -> a -> m b rowMonadicWith bempty bappend (Colonnade v) g a = foldlM ( \bl e -> do br <- g (oneColonnadeEncode e a) return (bappend bl br) ) bempty v header :: (c1 -> c2) -> Colonnade Headed a c1 -> Vector c2 header g (Colonnade v) = Vector.map (g . getHeaded . oneColonnadeHead) v {- | This function is a helper for abusing 'Foldable' to optionally render a header. Its future is uncertain. -} headerMonadicGeneral :: (Monad m, Monoid b, Foldable h) => Colonnade h a c -> (c -> m b) -> m b headerMonadicGeneral (Colonnade v) g = id $ fmap (mconcat . Vector.toList) $ Vector.mapM (foldlMapM g . oneColonnadeHead) v headerMonadic :: (Monad m, Monoid b) => Colonnade Headed a c -> (c -> m b) -> m b headerMonadic (Colonnade v) g = fmap (mconcat . Vector.toList) $ Vector.mapM (g . getHeaded . oneColonnadeHead) v headerMonadicGeneral_ :: (Monad m, Headedness h) => Colonnade h a c -> (c -> m b) -> m () headerMonadicGeneral_ (Colonnade v) g = case headednessExtract of Nothing -> return () Just f -> Vector.mapM_ (g . f . oneColonnadeHead) v headerMonoidalGeneral :: (Monoid m, Foldable h) => Colonnade h a c -> (c -> m) -> m headerMonoidalGeneral (Colonnade v) g = foldMap (foldMap g . oneColonnadeHead) v headerMonoidalFull :: (Monoid m) => Colonnade h a c -> (h c -> m) -> m headerMonoidalFull (Colonnade v) g = foldMap (g . oneColonnadeHead) v headerMonadic_ :: (Monad m) => Colonnade Headed a c -> (c -> m b) -> m () headerMonadic_ (Colonnade v) g = Vector.mapM_ (g . getHeaded . oneColonnadeHead) v foldlMapM :: (Foldable t, Monoid b, Monad m) => (a -> m b) -> t a -> m b foldlMapM f = foldlM (\b a -> fmap (mappend b) (f a)) mempty discard :: Cornice h p a c -> Colonnade h a c discard = go where go :: forall h p a c. Cornice h p a c -> Colonnade h a c go (CorniceBase c) = c go (CorniceCap children) = Colonnade (getColonnade . go . oneCorniceBody =<< children) endow :: forall p a c. (c -> c -> c) -> Cornice Headed p a c -> Colonnade Headed a c endow f x = case x of CorniceBase colonnade -> colonnade CorniceCap v -> Colonnade (V.concatMap (\(OneCornice h b) -> go h b) v) where go :: forall p'. c -> Cornice Headed p' a c -> Vector (OneColonnade Headed a c) go c (CorniceBase (Colonnade v)) = V.map (mapOneColonnadeHeader (f c)) v go c (CorniceCap v) = V.concatMap (\(OneCornice h b) -> go (f c h) b) v uncapAnnotated :: forall sz p a c h. AnnotatedCornice sz h p a c -> Colonnade (Sized sz h) a c uncapAnnotated x = case x of AnnotatedCorniceBase _ colonnade -> colonnade AnnotatedCorniceCap _ v -> Colonnade (V.concatMap (\(OneCornice _ b) -> go b) v) where go :: forall p'. AnnotatedCornice sz h p' a c -> Vector (OneColonnade (Sized sz h) a c) go (AnnotatedCorniceBase _ (Colonnade v)) = v go (AnnotatedCorniceCap _ v) = V.concatMap (\(OneCornice _ b) -> go b) v annotate :: Cornice Headed p a c -> AnnotatedCornice (Maybe Int) Headed p a c annotate = go where go :: forall p a c. Cornice Headed p a c -> AnnotatedCornice (Maybe Int) Headed p a c go (CorniceBase c) = let len = V.length (getColonnade c) in AnnotatedCorniceBase (if len > 0 then (Just len) else Nothing) (mapHeadedness (Sized (Just 1)) c) go (CorniceCap children) = let annChildren = fmap (mapOneCorniceBody go) children in AnnotatedCorniceCap ( ( ( V.foldl' (combineJustInt (+)) ) Nothing . V.map (size . oneCorniceBody) ) annChildren ) annChildren combineJustInt :: (Int -> Int -> Int) -> Maybe Int -> Maybe Int -> Maybe Int combineJustInt f acc el = case acc of Nothing -> case el of Nothing -> Nothing Just i -> Just i Just i -> case el of Nothing -> Just i Just j -> Just (f i j) mapJustInt :: (Int -> Int) -> Maybe Int -> Maybe Int mapJustInt _ Nothing = Nothing mapJustInt f (Just i) = Just (f i) annotateFinely :: (Foldable f) => -- | fold function (Int -> Int -> Int) -> -- | finalize (Int -> Int) -> -- | Get size from content (c -> Int) -> f a -> Cornice Headed p a c -> AnnotatedCornice (Maybe Int) Headed p a c annotateFinely g finish toSize xs cornice = runST $ do m <- newMutableSizedCornice cornice sizeColonnades toSize xs m freezeMutableSizedCornice g finish m sizeColonnades :: forall f s p a c. (Foldable f) => -- | Get size from content (c -> Int) -> f a -> MutableSizedCornice s p a c -> ST s () sizeColonnades toSize xs cornice = do goHeader cornice mapM_ (goRow cornice) xs where goRow :: forall p'. MutableSizedCornice s p' a c -> a -> ST s () goRow (MutableSizedCorniceBase c) a = rowUpdateSize toSize c a goRow (MutableSizedCorniceCap children) a = mapM_ (flip goRow a . oneCorniceBody) children goHeader :: forall p'. MutableSizedCornice s p' a c -> ST s () goHeader (MutableSizedCorniceBase c) = headerUpdateSize toSize c goHeader (MutableSizedCorniceCap children) = mapM_ (goHeader . oneCorniceBody) children freezeMutableSizedCornice :: forall s p a c. -- | fold function (Int -> Int -> Int) -> -- | finalize (Int -> Int) -> MutableSizedCornice s p a c -> ST s (AnnotatedCornice (Maybe Int) Headed p a c) freezeMutableSizedCornice step finish = go where go :: forall p' a' c'. MutableSizedCornice s p' a' c' -> ST s (AnnotatedCornice (Maybe Int) Headed p' a' c') go (MutableSizedCorniceBase msc) = do szCol <- freezeMutableSizedColonnade msc let sz = ( mapJustInt finish . V.foldl' (combineJustInt step) Nothing . V.map (sizedSize . oneColonnadeHead) ) (getColonnade szCol) return (AnnotatedCorniceBase sz szCol) go (MutableSizedCorniceCap v1) = do v2 <- V.mapM (traverseOneCorniceBody go) v1 let sz = ( mapJustInt finish . V.foldl' (combineJustInt step) Nothing . V.map (size . oneCorniceBody) ) v2 return $ AnnotatedCorniceCap sz v2 newMutableSizedCornice :: forall s p a c. Cornice Headed p a c -> ST s (MutableSizedCornice s p a c) newMutableSizedCornice = go where go :: forall p'. Cornice Headed p' a c -> ST s (MutableSizedCornice s p' a c) go (CorniceBase c) = fmap MutableSizedCorniceBase (newMutableSizedColonnade c) go (CorniceCap v) = fmap MutableSizedCorniceCap (V.mapM (traverseOneCorniceBody go) v) traverseOneCorniceBody :: (Monad m) => (k p a c -> m (j p a c)) -> OneCornice k p a c -> m (OneCornice j p a c) traverseOneCorniceBody f (OneCornice h b) = fmap (OneCornice h) (f b) mapHeadedness :: (forall x. h x -> h' x) -> Colonnade h a c -> Colonnade h' a c mapHeadedness f (Colonnade v) = Colonnade (V.map (\(OneColonnade h c) -> OneColonnade (f h) c) v) -- | This is an O(1) operation, sort of size :: AnnotatedCornice sz h p a c -> sz size x = case x of AnnotatedCorniceBase m _ -> m AnnotatedCorniceCap sz _ -> sz mapOneCorniceBody :: (forall p' a' c'. k p' a' c' -> j p' a' c') -> OneCornice k p a c -> OneCornice j p a c mapOneCorniceBody f (OneCornice h b) = OneCornice h (f b) mapOneColonnadeHeader :: (Functor h) => (c -> c) -> OneColonnade h a c -> OneColonnade h a c mapOneColonnadeHeader f (OneColonnade h b) = OneColonnade (fmap f h) b headersMonoidal :: forall sz r m c p a h. (Monoid m, Headedness h) => -- | Apply the Fascia header row content Maybe (Fascia p r, r -> m -> m) -> -- | Build content from cell content and size [(sz -> c -> m, m -> m)] -> AnnotatedCornice sz h p a c -> m headersMonoidal wrapRow fromContentList = go wrapRow where go :: forall p'. Maybe (Fascia p' r, r -> m -> m) -> AnnotatedCornice sz h p' a c -> m go ef (AnnotatedCorniceBase _ (Colonnade v)) = let g :: m -> m g m = case ef of Nothing -> m Just (FasciaBase r, f) -> f r m in case headednessExtract of Just unhead -> g $ foldMap ( \(fromContent, wrap) -> wrap ( foldMap ( \(OneColonnade (Sized sz h) _) -> (fromContent sz (unhead h)) ) v ) ) fromContentList Nothing -> mempty go ef (AnnotatedCorniceCap _ v) = let g :: m -> m g m = case ef of Nothing -> m Just (FasciaCap r _, f) -> f r m in g ( foldMap ( \(fromContent, wrap) -> wrap ( foldMap ( \(OneCornice h b) -> (fromContent (size b) h) ) v ) ) fromContentList ) <> case ef of Nothing -> case flattenAnnotated v of Nothing -> mempty Just annCoreNext -> go Nothing annCoreNext Just (FasciaCap _ fn, f) -> case flattenAnnotated v of Nothing -> mempty Just annCoreNext -> go (Just (fn, f)) annCoreNext flattenAnnotated :: Vector (OneCornice (AnnotatedCornice sz h) p a c) -> Maybe (AnnotatedCornice sz h p a c) flattenAnnotated v = case v V.!? 0 of Nothing -> Nothing Just (OneCornice _ x) -> Just $ case x of AnnotatedCorniceBase m _ -> flattenAnnotatedBase m v AnnotatedCorniceCap m _ -> flattenAnnotatedCap m v flattenAnnotatedBase :: sz -> Vector (OneCornice (AnnotatedCornice sz h) Base a c) -> AnnotatedCornice sz h Base a c flattenAnnotatedBase msz = AnnotatedCorniceBase msz . Colonnade . V.concatMap (\(OneCornice _ (AnnotatedCorniceBase _ (Colonnade v))) -> v) flattenAnnotatedCap :: sz -> Vector (OneCornice (AnnotatedCornice sz h) (Cap p) a c) -> AnnotatedCornice sz h (Cap p) a c flattenAnnotatedCap m = AnnotatedCorniceCap m . V.concatMap getTheVector getTheVector :: OneCornice (AnnotatedCornice sz h) (Cap p) a c -> Vector (OneCornice (AnnotatedCornice sz h) p a c) getTheVector (OneCornice _ (AnnotatedCorniceCap _ v)) = v data MutableSizedCornice s (p :: Pillar) a c where MutableSizedCorniceBase :: {-# UNPACK #-} !(MutableSizedColonnade s Headed a c) -> MutableSizedCornice s Base a c MutableSizedCorniceCap :: {-# UNPACK #-} !(Vector (OneCornice (MutableSizedCornice s) p a c)) -> MutableSizedCornice s (Cap p) a c data MutableSizedColonnade s h a c = MutableSizedColonnade { _mutableSizedColonnadeColumns :: {-# UNPACK #-} !(Vector (OneColonnade h a c)) , _mutableSizedColonnadeSizes :: {-# UNPACK #-} !(MVU.STVector s Int) } {- | As the first argument to the 'Colonnade' type constructor, this indictates that the columnar encoding has a header. This type is isomorphic to 'Identity' but is given a new name to clarify its intent: > example :: Colonnade Headed Foo Text The term @example@ represents a columnar encoding of @Foo@ in which the columns have headings. -} newtype Headed a = Headed {getHeaded :: a} deriving (Eq, Ord, Functor, Show, Read, Foldable) instance Applicative Headed where pure = Headed Headed f <*> Headed a = Headed (f a) {- | As the first argument to the 'Colonnade' type constructor, this indictates that the columnar encoding does not have a header. This type is isomorphic to 'Proxy' but is given a new name to clarify its intent: > example :: Colonnade Headless Foo Text The term @example@ represents a columnar encoding of @Foo@ in which the columns do not have headings. -} data Headless a = Headless deriving (Eq, Ord, Functor, Show, Read, Foldable) instance Applicative Headless where pure _ = Headless Headless <*> Headless = Headless data Sized sz f a = Sized { sizedSize :: !sz , sizedContent :: !(f a) } deriving (Functor, Foldable) instance Contravariant Headless where contramap _ Headless = Headless -- | Encodes a header and a cell. data OneColonnade h a c = OneColonnade { oneColonnadeHead :: !(h c) , oneColonnadeEncode :: !(a -> c) } deriving (Functor) instance (Functor h) => Profunctor (OneColonnade h) where rmap = fmap lmap f (OneColonnade h e) = OneColonnade h (e . f) {- | An columnar encoding of @a@. The type variable @h@ determines what is present in each column in the header row. It is typically instantiated to 'Headed' and occasionally to 'Headless'. There is nothing that restricts it to these two types, although they satisfy the majority of use cases. The type variable @c@ is the content type. This can be @Text@, @String@, or @ByteString@. In the companion libraries @reflex-dom-colonnade@ and @yesod-colonnade@, additional types that represent HTML with element attributes are provided that serve as the content type. Presented more visually: > +---- Value consumed to build a row > | > v > Colonnade h a c > ^ ^ > | | > | +-- Content (Text, ByteString, Html, etc.) > | > +------ Headedness (Headed or Headless) Internally, a 'Colonnade' is represented as a 'Vector' of individual column encodings. It is possible to use any collection type with 'Alternative' and 'Foldable' instances. However, 'Vector' was chosen to optimize the data structure for the use case of building the structure once and then folding over it many times. It is recommended that 'Colonnade's are defined at the top-level so that GHC avoids reconstructing them every time they are used. -} newtype Colonnade h a c = Colonnade { getColonnade :: Vector (OneColonnade h a c) } deriving (Monoid, Functor) instance (Functor h) => Profunctor (Colonnade h) where rmap = fmap lmap f (Colonnade v) = Colonnade (Vector.map (lmap f) v) instance Semigroup (Colonnade h a c) where Colonnade a <> Colonnade b = Colonnade (a Vector.++ b) sconcat xs = Colonnade (vectorConcatNE (fmap getColonnade xs)) {- | Isomorphic to the natural numbers. Only the promoted version of this type is used. -} data Pillar = Cap !Pillar | Base class ToEmptyCornice (p :: Pillar) where toEmptyCornice :: Cornice h p a c instance ToEmptyCornice Base where toEmptyCornice = CorniceBase mempty instance ToEmptyCornice (Cap p) where toEmptyCornice = CorniceCap Vector.empty data Fascia (p :: Pillar) r where FasciaBase :: !r -> Fascia Base r FasciaCap :: !r -> Fascia p r -> Fascia (Cap p) r data OneCornice k (p :: Pillar) a c = OneCornice { oneCorniceHead :: !c , oneCorniceBody :: !(k p a c) } deriving (Functor) data Cornice h (p :: Pillar) a c where CorniceBase :: !(Colonnade h a c) -> Cornice h Base a c CorniceCap :: {-# UNPACK #-} !(Vector (OneCornice (Cornice h) p a c)) -> Cornice h (Cap p) a c instance (Functor h) => Functor (Cornice h p a) where fmap f x = case x of CorniceBase c -> CorniceBase (fmap f c) CorniceCap c -> CorniceCap (mapVectorCornice f c) instance (Functor h) => Profunctor (Cornice h p) where rmap = fmap lmap f x = case x of CorniceBase c -> CorniceBase (lmap f c) CorniceCap c -> CorniceCap (contramapVectorCornice f c) instance Semigroup (Cornice h p a c) where CorniceBase a <> CorniceBase b = CorniceBase (mappend a b) CorniceCap a <> CorniceCap b = CorniceCap (a Vector.++ b) sconcat xs@(x :| _) = case x of CorniceBase _ -> CorniceBase (Colonnade (vectorConcatNE (fmap (getColonnade . getCorniceBase) xs))) CorniceCap _ -> CorniceCap (vectorConcatNE (fmap getCorniceCap xs)) instance (ToEmptyCornice p) => Monoid (Cornice h p a c) where mempty = toEmptyCornice mappend = (Semigroup.<>) mconcat xs1 = case xs1 of [] -> toEmptyCornice x : xs2 -> Semigroup.sconcat (x :| xs2) mapVectorCornice :: (Functor h) => (c -> d) -> Vector (OneCornice (Cornice h) p a c) -> Vector (OneCornice (Cornice h) p a d) mapVectorCornice f = V.map (fmap f) contramapVectorCornice :: (Functor h) => (b -> a) -> Vector (OneCornice (Cornice h) p a c) -> Vector (OneCornice (Cornice h) p b c) contramapVectorCornice f = V.map (lmapOneCornice f) lmapOneCornice :: (Functor h) => (b -> a) -> OneCornice (Cornice h) p a c -> OneCornice (Cornice h) p b c lmapOneCornice f (OneCornice theHead theBody) = OneCornice theHead (lmap f theBody) getCorniceBase :: Cornice h Base a c -> Colonnade h a c getCorniceBase (CorniceBase c) = c getCorniceCap :: Cornice h (Cap p) a c -> Vector (OneCornice (Cornice h) p a c) getCorniceCap (CorniceCap c) = c data AnnotatedCornice sz h (p :: Pillar) a c where AnnotatedCorniceBase :: !sz -> !(Colonnade (Sized sz h) a c) -> AnnotatedCornice sz h Base a c AnnotatedCorniceCap :: !sz -> {-# UNPACK #-} !(Vector (OneCornice (AnnotatedCornice sz h) p a c)) -> AnnotatedCornice sz h (Cap p) a c -- data MaybeInt = JustInt {-# UNPACK #-} !Int | NothingInt {- | This is provided with @vector-0.12@, but we include a copy here for compatibility. -} vectorConcatNE :: NonEmpty (Vector a) -> Vector a vectorConcatNE = Vector.concat . toList {- | This class communicates that a container holds either zero elements or one element. Furthermore, all inhabitants of the type must hold the same number of elements. Both 'Headed' and 'Headless' have instances. The following law accompanies any instances: > maybe x (\f -> f (headednessPure x)) headednessContents == x > todo: come up with another law that relates to Traversable Consequently, there is no instance for 'Maybe', which cannot satisfy the laws since it has inhabitants which hold different numbers of elements. 'Nothing' holds 0 elements and 'Just' holds 1 element. -} class Headedness h where headednessPure :: a -> h a headednessExtract :: Maybe (h a -> a) headednessExtractForall :: Maybe (ExtractForall h) instance Headedness Headed where headednessPure = Headed headednessExtract = Just getHeaded headednessExtractForall = Just (ExtractForall getHeaded) instance Headedness Headless where headednessPure _ = Headless headednessExtract = Nothing headednessExtractForall = Nothing newtype ExtractForall h = ExtractForall {runExtractForall :: forall a. h a -> a}