{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveFoldable #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# OPTIONS_HADDOCK not-home #-} {-# OPTIONS_GHC -Wall -fno-warn-unused-imports -fno-warn-unticked-promoted-constructors #-} -- | 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 Data.Vector (Vector) import Data.Foldable import Control.Monad.ST (ST,runST) import Data.Monoid import Data.Functor.Contravariant (Contravariant(..)) import Data.Profunctor (Profunctor(..)) import Data.Semigroup (Semigroup) import Data.List.NonEmpty (NonEmpty((:|))) import Data.Foldable (toList) import qualified Data.Semigroup as Semigroup import qualified Data.Vector as Vector import qualified Data.Vector as V import qualified Data.Vector.Unboxed.Mutable as MVU import qualified Data.Vector.Unboxed as VU import qualified Data.Vector as V import qualified Data.Vector as Vector import qualified Data.Vector.Generic as GV -- | 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 :: (c -> Int) -- ^ Get size from content -> 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 => (c -> Int) -- ^ Get size from content -> 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) => (c -> Int) -- ^ Get size from content -> 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 => (Int -> Int -> Int) -- ^ fold function -> (Int -> Int) -- ^ finalize -> (c -> Int) -- ^ Get size from content -> 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 => (c -> Int) -- ^ Get size from content -> 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. (Int -> Int -> Int) -- ^ fold function -> (Int -> Int) -- ^ finalize -> 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) => Maybe (Fascia p r, r -> m -> m) -- ^ Apply the Fascia header row content -> [(sz -> c -> m, m -> m)] -- ^ Build content from cell content and size -> 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 }