some changes

This commit is contained in:
Andrew Martin 2017-02-15 21:35:49 -05:00
parent 9a14ce158a
commit 5d268119ce
7 changed files with 539 additions and 119 deletions

View File

@ -301,40 +301,69 @@ builderCell = lazyTextCell . TBuilder.toLazyText
-- used to add attributes to the generated @\<tr\>@ elements. -- used to add attributes to the generated @\<tr\>@ elements.
encodeTable :: encodeTable ::
(Foldable f, Foldable h) (Foldable f, Foldable h)
=> Maybe Attribute -- ^ Attributes of @\<thead\>@, pass 'Nothing' to omit @\<thead\>@ => Maybe (Attribute,Attribute) -- ^ Attributes of @\<thead\>@ and its @\<tr\>@, pass 'Nothing' to omit @\<thead\>@
-> Attribute -- ^ Attributes of @\<tbody\>@ element -> Attribute -- ^ Attributes of @\<tbody\>@ element
-> (a -> Attribute) -- ^ Attributes of each @\<tr\>@ element -> (a -> Attribute) -- ^ Attributes of each @\<tr\>@ element
-> ((Html -> Html) -> c -> Html) -- ^ Wrap content and convert to 'Html' -> ((Html -> Html) -> c -> Html) -- ^ Wrap content and convert to 'Html'
-> Attribute -- ^ Attributes of @\<table\>@ element -> Attribute -- ^ Attributes of @\<table\>@ element
-> Colonnade h c a -- ^ How to encode data as a row -> Colonnade h a c -- ^ How to encode data as a row
-> f a -- ^ Collection of data -> f a -- ^ Collection of data
-> Html -> Html
encodeTable mtheadAttrs tbodyAttrs trAttrs wrapContent tableAttrs colonnade xs = encodeTable mtheadAttrs tbodyAttrs trAttrs wrapContent tableAttrs colonnade xs =
H.table ! tableAttrs $ do H.table ! tableAttrs $ do
for_ mtheadAttrs $ \theadAttrs -> do for_ mtheadAttrs $ \(theadAttrs,theadTrAttrs) -> do
H.thead ! theadAttrs $ do H.thead ! theadAttrs $ H.tr ! theadTrAttrs $ do
Encode.headerMonoidalGeneral colonnade (wrapContent H.th) Encode.headerMonoidalGeneral colonnade (wrapContent H.th)
H.tbody ! tbodyAttrs $ do encodeBody trAttrs wrapContent tbodyAttrs colonnade xs
forM_ xs $ \x -> do
H.tr ! trAttrs x $ Encode.rowMonoidal colonnade (wrapContent H.td) x encodeTieredHeaderTable :: Foldable f
=> Attribute -- ^ Attributes of @\<thead\>@
-> Attribute -- ^ Attributes of @\<tbody\>@ element
-> (a -> Attribute) -- ^ Attributes of each @\<tr\>@ element in the @\<tbody\>@
-> ((Html -> Html) -> c -> Html) -- ^ Wrap content and convert to 'Html'
-> Attribute -- ^ Attributes of @\<table\>@ element
-> Fascia p Attribute -- ^ Attributes for @\<tr\>@ elements in the @\<thead\>@
-> Cornice p a c
-> f a -- ^ Collection of data
-> Html
encodeTieredHeaderTable theadAttrs tbodyAttrs trAttrs wrapContent tableAttrs cornice xs = do
let colonnade = CE.discard cornice
annCornice = annotate cornice
H.table ! tableAttrs $ do
H.thead ! theadAttrs $ H.tr ! trAttrs $ do
Encode.headerMonoidalGeneral colonnade (wrapContent H.th)
encodeBody trAttrs wrapContent tbodyAttrs colonnade xs
encodeBody :: (Foldable h, Foldable f)
=> (a -> Attribute) -- ^ Attributes of each @\<tr\>@ element
-> ((Html -> Html) -> c -> Html) -- ^ Wrap content and convert to 'Html'
-> Attribute -- ^ Attributes of @\<tbody\>@ element
-> Colonnade h a c -- ^ How to encode data as a row
-> f a -- ^ Collection of data
-> Html
encodeBody trAttrs wrapContent tbodyAttrs colonnade xs = do
H.tbody ! tbodyAttrs $ do
forM_ xs $ \x -> do
H.tr ! trAttrs x $ Encode.rowMonoidal colonnade (wrapContent H.td) x
-- | Encode a table with a header. Table cells may have attributes -- | Encode a table with a header. Table cells may have attributes
-- applied to them. -- applied to them.
encodeHeadedCellTable :: encodeHeadedCellTable ::
Foldable f Foldable f
=> Attribute -- ^ Attributes of @\<table\>@ element => Attribute -- ^ Attributes of @\<table\>@ element
-> Colonnade Headed Cell a -- ^ How to encode data as columns -> Colonnade Headed a Cell -- ^ How to encode data as columns
-> f a -- ^ Collection of data -> f a -- ^ Collection of data
-> Html -> Html
encodeHeadedCellTable = encodeTable encodeHeadedCellTable = encodeTable
(Just mempty) mempty (const mempty) htmlFromCell (Just (mempty,mempty)) mempty (const mempty) htmlFromCell
-- | Encode a table without a header. Table cells may have attributes -- | Encode a table without a header. Table cells may have attributes
-- applied to them. -- applied to them.
encodeHeadlessCellTable :: encodeHeadlessCellTable ::
Foldable f Foldable f
=> Attribute -- ^ Attributes of @\<table\>@ element => Attribute -- ^ Attributes of @\<table\>@ element
-> Colonnade Headless Cell a -- ^ How to encode data as columns -> Colonnade Headless a Cell -- ^ How to encode data as columns
-> f a -- ^ Collection of data -> f a -- ^ Collection of data
-> Html -> Html
encodeHeadlessCellTable = encodeTable encodeHeadlessCellTable = encodeTable
@ -345,18 +374,18 @@ encodeHeadlessCellTable = encodeTable
encodeHeadedHtmlTable :: encodeHeadedHtmlTable ::
Foldable f Foldable f
=> Attribute -- ^ Attributes of @\<table\>@ element => Attribute -- ^ Attributes of @\<table\>@ element
-> Colonnade Headed Html a -- ^ How to encode data as columns -> Colonnade Headed a Html -- ^ How to encode data as columns
-> f a -- ^ Collection of data -> f a -- ^ Collection of data
-> Html -> Html
encodeHeadedHtmlTable = encodeTable encodeHeadedHtmlTable = encodeTable
(Just mempty) mempty (const mempty) ($) (Just (mempty,mempty)) mempty (const mempty) ($)
-- | Encode a table without a header. Table cells cannot have attributes -- | Encode a table without a header. Table cells cannot have attributes
-- applied to them. -- applied to them.
encodeHeadlessHtmlTable :: encodeHeadlessHtmlTable ::
Foldable f Foldable f
=> Attribute -- ^ Attributes of @\<table\>@ element => Attribute -- ^ Attributes of @\<table\>@ element
-> Colonnade Headless Html a -- ^ How to encode data as columns -> Colonnade Headless a Html -- ^ How to encode data as columns
-> f a -- ^ Collection of data -> f a -- ^ Collection of data
-> Html -> Html
encodeHeadlessHtmlTable = encodeTable encodeHeadlessHtmlTable = encodeTable

View File

@ -31,6 +31,7 @@ library
Colonnade Colonnade
Colonnade.Encode Colonnade.Encode
Colonnade.Internal Colonnade.Internal
Colonnade.Cornice.Encode
build-depends: build-depends:
base >= 4.7 && < 5 base >= 4.7 && < 5
, contravariant >= 1.2 && < 1.5 , contravariant >= 1.2 && < 1.5

View File

@ -1,12 +1,19 @@
-- | Build backend-agnostic columnar encodings that can be -- | Build backend-agnostic columnar encodings that can be
-- used to visualize tabular data. -- used to visualize tabular data.
module Colonnade module Colonnade
( -- * Example ( -- * Example
-- $setup -- $setup
-- * Types -- * Types
-- ** Colonnade
Colonnade Colonnade
, Headed , Headed
, Headless , Headless
-- ** Cornice
, Cornice
, Pillar(..)
, Fascia(..)
-- * Create -- * Create
, headed , headed
, headless , headless
@ -17,18 +24,19 @@ module Colonnade
, bool , bool
, replaceWhen , replaceWhen
, modifyWhen , modifyWhen
, mapContent -- * Cornice
, cap
, recap
-- * Ascii Table -- * Ascii Table
, ascii , ascii
) where ) where
import Colonnade.Internal import Colonnade.Internal
import qualified Colonnade.Encode as Encode
import Data.Vector (Vector)
import Data.Foldable import Data.Foldable
import Data.Monoid (Endo(..)) import Data.Monoid (Endo(..))
import Control.Monad import Control.Monad
import Data.Functor.Contravariant import qualified Colonnade.Encode as Encode
import qualified Colonnade.Cornice.Encode as CE
import qualified Data.Bool import qualified Data.Bool
import qualified Data.Maybe import qualified Data.Maybe
import qualified Data.List as List import qualified Data.List as List
@ -40,7 +48,7 @@ import qualified Data.Vector as Vector
-- used for the remainder of the examples in the docs: -- used for the remainder of the examples in the docs:
-- --
-- >>> import Data.Monoid (mconcat,(<>)) -- >>> import Data.Monoid (mconcat,(<>))
-- >>> import Data.Functor.Contravariant (contramap) -- >>> import Data.Profunctor (lmap)
-- --
-- The data types we wish to encode are: -- The data types we wish to encode are:
-- --
@ -51,7 +59,7 @@ import qualified Data.Vector as Vector
-- One potential columnar encoding of a @Person@ would be: -- One potential columnar encoding of a @Person@ would be:
-- --
-- >>> :{ -- >>> :{
-- let colPerson :: Colonnade Headed String Person -- let colPerson :: Colonnade Headed Person String
-- colPerson = mconcat -- colPerson = mconcat
-- [ headed "Name" name -- [ headed "Name" name
-- , headed "Age" (show . age) -- , headed "Age" (show . age)
@ -76,7 +84,7 @@ import qualified Data.Vector as Vector
-- --
-- >>> let showDollar = (('$':) . show) :: Int -> String -- >>> let showDollar = (('$':) . show) :: Int -> String
-- >>> :{ -- >>> :{
-- let encodingHouse :: Colonnade Headed String House -- let encodingHouse :: Colonnade Headed House String
-- encodingHouse = mconcat -- encodingHouse = mconcat
-- [ headed "Color" (show . color) -- [ headed "Color" (show . color)
-- , headed "Price" (showDollar . price) -- , headed "Price" (showDollar . price)
@ -95,15 +103,15 @@ import qualified Data.Vector as Vector
-- | A single column with a header. -- | A single column with a header.
headed :: c -> (a -> c) -> Colonnade Headed c a headed :: c -> (a -> c) -> Colonnade Headed a c
headed h = singleton (Headed h) headed h = singleton (Headed h)
-- | A single column without a header. -- | A single column without a header.
headless :: (a -> c) -> Colonnade Headless c a headless :: (a -> c) -> Colonnade Headless a c
headless = singleton Headless headless = singleton Headless
-- | A single column with any kind of header. This is not typically needed. -- | A single column with any kind of header. This is not typically needed.
singleton :: f c -> (a -> c) -> Colonnade f c a singleton :: f c -> (a -> c) -> Colonnade f a c
singleton h = Colonnade . Vector.singleton . OneColonnade h singleton h = Colonnade . Vector.singleton . OneColonnade h
-- | Lift a column over a 'Maybe'. For example, if some people -- | Lift a column over a 'Maybe'. For example, if some people
@ -123,10 +131,10 @@ singleton h = Colonnade . Vector.singleton . OneColonnade h
-- the help of 'fromMaybe': -- the help of 'fromMaybe':
-- --
-- >>> :{ -- >>> :{
-- let colOwners :: Colonnade Headed String (Person,Maybe House) -- let colOwners :: Colonnade Headed (Person,Maybe House) String
-- colOwners = mconcat -- colOwners = mconcat
-- [ contramap fst colPerson -- [ lmap fst colPerson
-- , contramap snd (fromMaybe "" encodingHouse) -- , lmap snd (fromMaybe "" encodingHouse)
-- ] -- ]
-- :} -- :}
-- --
@ -138,7 +146,7 @@ singleton h = Colonnade . Vector.singleton . OneColonnade h
-- | Ruth | 25 | Red | $125000 | -- | Ruth | 25 | Red | $125000 |
-- | Sonia | 12 | Green | $145000 | -- | Sonia | 12 | Green | $145000 |
-- +--------+-----+-------+---------+ -- +--------+-----+-------+---------+
fromMaybe :: c -> Colonnade f c a -> Colonnade f c (Maybe a) fromMaybe :: c -> Colonnade f a c -> Colonnade f (Maybe a) c
fromMaybe c (Colonnade v) = Colonnade $ flip Vector.map v $ fromMaybe c (Colonnade v) = Colonnade $ flip Vector.map v $
\(OneColonnade h encode) -> OneColonnade h (maybe c encode) \(OneColonnade h encode) -> OneColonnade h (maybe c encode)
@ -150,10 +158,10 @@ fromMaybe c (Colonnade v) = Colonnade $ flip Vector.map v $
-- >>> let allColors = [Red,Green,Blue] -- >>> let allColors = [Red,Green,Blue]
-- >>> let encColor = columns (\c1 c2 -> if c1 == c2 then "✓" else "") (Headed . show) allColors -- >>> let encColor = columns (\c1 c2 -> if c1 == c2 then "✓" else "") (Headed . show) allColors
-- >>> :t encColor -- >>> :t encColor
-- encColor :: Colonnade Headed [Char] Color -- encColor :: Colonnade Headed Color [Char]
-- >>> let encHouse = headed "Price" (showDollar . price) <> contramap color encColor -- >>> let encHouse = headed "Price" (showDollar . price) <> lmap color encColor
-- >>> :t encHouse -- >>> :t encHouse
-- encHouse :: Colonnade Headed [Char] House -- encHouse :: Colonnade Headed House [Char]
-- >>> putStr (ascii encHouse houses) -- >>> putStr (ascii encHouse houses)
-- +---------+-----+-------+------+ -- +---------+-----+-------+------+
-- | Price | Red | Green | Blue | -- | Price | Red | Green | Blue |
@ -166,7 +174,7 @@ columns :: Foldable g
=> (b -> a -> c) -- ^ Cell content function => (b -> a -> c) -- ^ Cell content function
-> (b -> f c) -- ^ Header content function -> (b -> f c) -- ^ Header content function
-> g b -- ^ Basis for column encodings -> g b -- ^ Basis for column encodings
-> Colonnade f c a -> Colonnade f a c
columns getCell getHeader = id columns getCell getHeader = id
. Colonnade . Colonnade
. Vector.map (\b -> OneColonnade (getHeader b) (getCell b)) . Vector.map (\b -> OneColonnade (getHeader b) (getCell b))
@ -178,7 +186,7 @@ bool ::
-> (a -> Bool) -- ^ Predicate -> (a -> Bool) -- ^ Predicate
-> (a -> c) -- ^ Contents when predicate is false -> (a -> c) -- ^ Contents when predicate is false
-> (a -> c) -- ^ Contents when predicate is true -> (a -> c) -- ^ Contents when predicate is true
-> Colonnade f c a -> Colonnade f a c
bool h p onTrue onFalse = singleton h (Data.Bool.bool <$> onFalse <*> onTrue <*> p) bool h p onTrue onFalse = singleton h (Data.Bool.bool <$> onFalse <*> onTrue <*> p)
-- | Modify the contents of cells in rows whose values satisfy the -- | Modify the contents of cells in rows whose values satisfy the
@ -188,8 +196,8 @@ bool h p onTrue onFalse = singleton h (Data.Bool.bool <$> onFalse <*> onTrue <*>
modifyWhen :: modifyWhen ::
(c -> c) -- ^ Content change (c -> c) -- ^ Content change
-> (a -> Bool) -- ^ Row predicate -> (a -> Bool) -- ^ Row predicate
-> Colonnade f c a -- ^ Original 'Colonnade' -> Colonnade f a c -- ^ Original 'Colonnade'
-> Colonnade f c a -> Colonnade f a c
modifyWhen changeContent p (Colonnade v) = Colonnade modifyWhen changeContent p (Colonnade v) = Colonnade
( Vector.map ( Vector.map
(\(OneColonnade h encode) -> OneColonnade h $ \a -> (\(OneColonnade h encode) -> OneColonnade h $ \a ->
@ -202,8 +210,8 @@ modifyWhen changeContent p (Colonnade v) = Colonnade
replaceWhen :: replaceWhen ::
c -- ^ New content c -- ^ New content
-> (a -> Bool) -- ^ Row predicate -> (a -> Bool) -- ^ Row predicate
-> Colonnade f c a -- ^ Original 'Colonnade' -> Colonnade f a c -- ^ Original 'Colonnade'
-> Colonnade f c a -> Colonnade f a c
replaceWhen newContent p (Colonnade v) = Colonnade replaceWhen newContent p (Colonnade v) = Colonnade
( Vector.map ( Vector.map
(\(OneColonnade h encode) -> OneColonnade h $ \a -> (\(OneColonnade h encode) -> OneColonnade h $ \a ->
@ -211,69 +219,69 @@ replaceWhen newContent p (Colonnade v) = Colonnade
) v ) v
) )
-- | 'Colonnade' is covariant in its content type. Consequently, it can be toCornice :: Colonnade Headed a c -> Cornice Base a c
-- mapped over. There is no standard typeclass for types that are covariant toCornice = CorniceBase
-- in their second-to-last argument, so this function is provided for
-- situations that require this. cap :: c -> Cornice p a c -> Cornice (Cap p) a c
mapContent :: Functor f => (c1 -> c2) -> Colonnade f c1 a -> Colonnade f c2 a cap h cor = CorniceCap (V.singleton (OneCornice h cor))
mapContent f (Colonnade v) = Colonnade
$ Vector.map (\(OneColonnade h c) -> (OneColonnade (fmap f h) (f . c))) v
asciiMulti :: Foldable f
=> Cornice p a String -- ^ columnar encoding
-> f a -- ^ rows
-> String
asciiMulti cor xs =
let annCor = CE.annotateFinely (\x y -> x + y + 3) id
List.length xs cor
in CE.headersMonoidal (Right (\s -> s ++ "\n")) (\sz c -> rightPad sz ' ' c) annCor
-- | Render a collection of rows as an ascii table. The table\'s columns are -- | Render a collection of rows as an ascii table. The table\'s columns are
-- specified by the given 'Colonnade'. This implementation is inefficient and -- specified by the given 'Colonnade'. This implementation is inefficient and
-- does not provide any wrapping behavior. It is provided so that users can -- does not provide any wrapping behavior. It is provided so that users can
-- try out @colonnade@ in ghci and so that @doctest@ can verify examples -- try out @colonnade@ in ghci and so that @doctest@ can verify example
-- code in the haddocks. -- code in the haddocks.
ascii :: Foldable f ascii :: Foldable f
=> Colonnade Headed String a -- ^ columnar encoding => Colonnade Headed a String -- ^ columnar encoding
-> f a -- ^ rows -> f a -- ^ rows
-> String -> String
ascii enc xs = ascii col xs =
let theHeader :: [(Int,String)] let sizedCol = Encode.sizeColumns List.length xs col
theHeader = (zip (enumFrom 0) . map (\s -> " " ++ s ++ " ")) (toList (Encode.header id enc)) divider = concat
theBody :: [[(Int,String)]] [ "+"
theBody = map (zip (enumFrom 0) . map (\s -> " " ++ s ++ " ") . toList . Encode.row id enc) (toList xs) , Encode.headerMonoidalFull sizedCol
sizes :: [Int] (\(Sized sz _) -> hyphens (sz + 2) ++ "+")
sizes = ($ replicate (length theHeader) 1) $ appEndo $ mconcat , "\n"
[ foldMap (\(i,str) -> Endo (replaceAt i (length str))) theHeader
, (foldMap . foldMap) (\(i,str) -> Endo (replaceAt i (length str))) theBody
] ]
paddedHeader :: [String] rowContents = foldMap
paddedHeader = map (\(i,str) -> rightPad (atDef 1 sizes i) ' ' str) theHeader (\x -> concat
paddedBody :: [[String]] [ "|"
paddedBody = (map . map) (\(i,str) -> rightPad (atDef 1 sizes i) ' ' str) theBody , Encode.rowMonoidalHeader
divider :: String sizedCol
divider = "+" ++ join (List.intersperse "+" (map (\i -> replicate i '-') sizes)) ++ "+" (\(Sized sz _) c -> " " ++ rightPad sz ' ' c ++ " |")
headerStr :: String x
headerStr = "|" ++ join (List.intersperse "|" paddedHeader) ++ "|" , "\n"
bodyStr :: String ]
bodyStr = List.unlines (map ((\s -> "|" ++ s ++ "|") . join . List.intersperse "|") paddedBody) ) xs
in divider ++ "\n" ++ headerStr in List.concat
++ "\n" ++ divider [ divider
++ "\n" ++ bodyStr ++ divider ++ "\n" , concat
[ "|"
, Encode.headerMonoidalFull sizedCol
-- this has no effect if the index is out of bounds (\(Sized s (Headed h)) -> " " ++ rightPad s ' ' h ++ " |")
replaceAt :: Ord a => Int -> a -> [a] -> [a] , "\n"
replaceAt _ _ [] = [] ]
replaceAt n v (a:as) = if n > 0 , divider
then a : replaceAt (n - 1) v as , rowContents
else (max v a) : as , divider
]
hyphens :: Int -> String
hyphens n = List.replicate n '-'
rightPad :: Int -> a -> [a] -> [a] rightPad :: Int -> a -> [a] -> [a]
rightPad m a xs = take m $ xs ++ repeat a rightPad m a xs = take m $ xs ++ repeat a
atDef :: a -> [a] -> Int -> a
atDef def = Data.Maybe.fromMaybe def .^ atMay where
(.^) f g x1 x2 = f (g x1 x2)
atMay = eitherToMaybe .^ at_
eitherToMaybe = either (const Nothing) Just
at_ xs o | o < 0 = Left $ "index must not be negative, index=" ++ show o
| otherwise = f o xs
where f 0 (z:_) = Right z
f i (_:zs) = f (i-1) zs
f i [] = Left $ "index too large, index=" ++ show o ++ ", length=" ++ show (o-i)
-- data Company = Company String String Int -- data Company = Company String String Int
-- --
-- data Company = Company -- data Company = Company

View File

@ -0,0 +1,203 @@
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE DataKinds #-}
{-# OPTIONS_GHC -Wall -fno-warn-unused-imports -fno-warn-unticked-promoted-constructors -Werror #-}
module Colonnade.Cornice.Encode
( annotate
, annotateFinely
, size
, endow
, discard
, headersMonoidal
) where
import Colonnade.Internal
import Data.Vector (Vector)
import Control.Monad.ST (ST,runST)
import Data.Monoid
import qualified Data.Vector as V
import qualified Colonnade.Encode as E
discard :: Cornice p a c -> Colonnade Headed a c
discard = go where
go :: forall p a c. Cornice p a c -> Colonnade Headed a c
go (CorniceBase c) = c
go (CorniceCap children) = Colonnade (getColonnade . go . oneCorniceBody =<< children)
endow :: forall p a c. (c -> c -> c) -> Cornice 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 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
annotate :: Cornice p a c -> AnnotatedCornice p a c
annotate = go where
go :: forall p a c. Cornice p a c -> AnnotatedCornice p a c
go (CorniceBase c) = AnnotatedCorniceBase (mapHeadedness (Sized 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 p a c
-> AnnotatedCornice 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 = E.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) = E.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 p a c)
freezeMutableSizedCornice step finish = go
where
go :: forall p' a' c'. MutableSizedCornice s p' a' c' -> ST s (AnnotatedCornice p' a' c')
go (MutableSizedCorniceBase msc) =
fmap AnnotatedCorniceBase (E.freezeMutableSizedColonnade msc)
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 p a c
-> ST s (MutableSizedCornice s p a c)
newMutableSizedCornice = go where
go :: forall p'. Cornice p' a c -> ST s (MutableSizedCornice s p' a c)
go (CorniceBase c) = fmap MutableSizedCorniceBase (E.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)
-- annotate ::
-- Int -- ^ initial
-- -> (Int -> Int -> Int) -- ^ fold function
-- -> (Int -> Int) -- ^ finalize
-- -> Cornice p a c
-- -> AnnotatedCornice p a c
-- annotate i0 g finish = go where
-- go :: forall p a c. Cornice p a c -> AnnotatedCornice p a c
-- go (CorniceBase c) = AnnotatedCorniceBase c
-- go (CorniceCap children) =
-- let annChildren = fmap (mapOneCorniceBody go) children
-- in AnnotatedCorniceCap ((finish . V.foldl' g i0 . V.map (size . oneCorniceBody)) annChildren) annChildren
-- | This is an O(1) operation, sort of
size :: AnnotatedCornice p a c -> Maybe Int
size x = case x of
AnnotatedCorniceBase (Colonnade v) -> if V.length v > 0
then Just ((V.sum . V.map (sizedSize . oneColonnadeHead)) v)
else Nothing
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 r m c p a.
Monoid m
=> Either (Fascia p r, r -> m -> m) (m -> m) -- ^ Apply the Fascia header row content
-> (Int -> c -> m) -- ^ Build content from cell content and size
-> AnnotatedCornice p a c
-> m
headersMonoidal wrapRow fromContent = go wrapRow
where
go :: forall p'. Either (Fascia p' r, r -> m -> m) (m -> m) -> AnnotatedCornice p' a c -> m
go ef (AnnotatedCorniceBase (Colonnade v)) =
let g :: m -> m
g m = case ef of
Right f -> f m
Left (FasciaBase r, f) -> f r m
in foldMap (\(OneColonnade (Sized sz (Headed h)) _) ->
g (fromContent sz h)) v
go ef (AnnotatedCorniceCap _ v) =
let g :: m -> m
g m = case ef of
Right f -> f m
Left (FasciaCap r _, f) -> f r m
in foldMap (\(OneCornice h b) ->
(case size b of
Nothing -> mempty
Just sz -> g (fromContent sz h))
) v
<> case ef of
Right f -> case flattenAnnotated v of
Nothing -> mempty
Just annCoreNext -> go (Right f) annCoreNext
Left (FasciaCap _ fn, f) -> case flattenAnnotated v of
Nothing -> mempty
Just annCoreNext -> go (Left (fn,f)) annCoreNext
flattenAnnotated :: Vector (OneCornice AnnotatedCornice p a c) -> Maybe (AnnotatedCornice p a c)
flattenAnnotated v = case v V.!? 0 of
Nothing -> Nothing
Just (OneCornice _ x) -> Just $ case x of
AnnotatedCorniceBase _ -> flattenAnnotatedBase v
AnnotatedCorniceCap m _ -> flattenAnnotatedCap m v
flattenAnnotatedBase :: Vector (OneCornice AnnotatedCornice Base a c) -> AnnotatedCornice Base a c
flattenAnnotatedBase = AnnotatedCorniceBase
. Colonnade
. V.concatMap
(\(OneCornice _ (AnnotatedCorniceBase (Colonnade v))) -> v)
flattenAnnotatedCap :: Maybe Int -> Vector (OneCornice AnnotatedCornice (Cap p) a c) -> AnnotatedCornice (Cap p) a c
flattenAnnotatedCap m = AnnotatedCorniceCap m . V.concatMap getTheVector
getTheVector :: OneCornice AnnotatedCornice (Cap p) a c -> Vector (OneCornice AnnotatedCornice p a c)
getTheVector (OneCornice _ (AnnotatedCorniceCap _ v)) = v

View File

@ -30,30 +30,43 @@ module Colonnade.Encode
, rowMonadic_ , rowMonadic_
, rowMonadicWith , rowMonadicWith
, rowMonoidal , rowMonoidal
, rowMonoidalHeader
, header , header
, headerMonadic , headerMonadic
, headerMonadic_ , headerMonadic_
, headerMonadicGeneral , headerMonadicGeneral
, headerMonadicGeneral_ , headerMonadicGeneral_
, headerMonoidalGeneral , headerMonoidalGeneral
, headerMonoidalFull
, bothMonadic_ , bothMonadic_
, freezeMutableSizedColonnade
, newMutableSizedColonnade
, rowUpdateSize
, headerUpdateSize
, sizeColumns
) where ) where
import Colonnade.Internal import Colonnade.Internal
import Data.Vector (Vector) import Data.Vector (Vector)
import Data.Foldable import Data.Foldable
import Control.Monad.ST (ST,runST)
import Data.Monoid
import qualified Data.Vector as Vector import qualified Data.Vector as Vector
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.Generic as GV
-- | Consider providing a variant the produces a list -- | Consider providing a variant the produces a list
-- instead. It may allow more things to get inlined -- instead. It may allow more things to get inlined
-- in to a loop. -- in to a loop.
row :: (c1 -> c2) -> Colonnade f c1 a -> a -> Vector c2 row :: (c1 -> c2) -> Colonnade f a c1 -> a -> Vector c2
row g (Colonnade v) a = flip Vector.map v $ row g (Colonnade v) a = flip Vector.map v $
\(OneColonnade _ encode) -> g (encode a) \(OneColonnade _ encode) -> g (encode a)
bothMonadic_ :: Monad m bothMonadic_ :: Monad m
=> Colonnade Headed content a => Colonnade Headed a c
-> (content -> content -> m b) -> (c -> c -> m b)
-> a -> a
-> m () -> m ()
bothMonadic_ (Colonnade v) g a = bothMonadic_ (Colonnade v) g a =
@ -61,8 +74,8 @@ bothMonadic_ (Colonnade v) g a =
rowMonadic :: rowMonadic ::
(Monad m, Monoid b) (Monad m, Monoid b)
=> Colonnade f content a => Colonnade f a c
-> (content -> m b) -> (c -> m b)
-> a -> a
-> m b -> m b
rowMonadic (Colonnade v) g a = rowMonadic (Colonnade v) g a =
@ -71,8 +84,8 @@ rowMonadic (Colonnade v) g a =
rowMonadic_ :: rowMonadic_ ::
Monad m Monad m
=> Colonnade f content a => Colonnade f a c
-> (content -> m b) -> (c -> m b)
-> a -> a
-> m () -> m ()
rowMonadic_ (Colonnade v) g a = rowMonadic_ (Colonnade v) g a =
@ -80,19 +93,75 @@ rowMonadic_ (Colonnade v) g a =
rowMonoidal :: rowMonoidal ::
Monoid m Monoid m
=> Colonnade h c a => Colonnade h a c
-> (c -> m) -> (c -> m)
-> a -> a
-> m -> m
rowMonoidal (Colonnade v) g a = rowMonoidal (Colonnade v) g a =
foldMap (\e -> g (oneColonnadeEncode e a)) v foldMap (\(OneColonnade h 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 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 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 sz h) enc)
$ V.zip v (GV.convert sizeVec)
rowMonadicWith :: rowMonadicWith ::
(Monad m) (Monad m)
=> b => b
-> (b -> b -> b) -> (b -> b -> b)
-> Colonnade f content a -> Colonnade f a c
-> (content -> m b) -> (c -> m b)
-> a -> a
-> m b -> m b
rowMonadicWith bempty bappend (Colonnade v) g a = rowMonadicWith bempty bappend (Colonnade v) g a =
@ -101,15 +170,15 @@ rowMonadicWith bempty bappend (Colonnade v) g a =
return (bappend bl br) return (bappend bl br)
) bempty v ) bempty v
header :: (c1 -> c2) -> Colonnade Headed c1 a -> Vector c2 header :: (c1 -> c2) -> Colonnade Headed a c1 -> Vector c2
header g (Colonnade v) = header g (Colonnade v) =
Vector.map (g . getHeaded . oneColonnadeHead) v Vector.map (g . getHeaded . oneColonnadeHead) v
-- | This function is a helper for abusing 'Foldable' to optionally -- | This function is a helper for abusing 'Foldable' to optionally
-- render a header. Its future is uncertain. -- render a header. Its future is uncertain.
headerMonadicGeneral :: (Monad m, Monoid b, Foldable h) headerMonadicGeneral :: (Monad m, Monoid b, Foldable h)
=> Colonnade h content a => Colonnade h a c
-> (content -> m b) -> (c -> m b)
-> m b -> m b
headerMonadicGeneral (Colonnade v) g = id headerMonadicGeneral (Colonnade v) g = id
$ fmap (mconcat . Vector.toList) $ fmap (mconcat . Vector.toList)
@ -117,36 +186,43 @@ headerMonadicGeneral (Colonnade v) g = id
headerMonadic :: headerMonadic ::
(Monad m, Monoid b) (Monad m, Monoid b)
=> Colonnade Headed content a => Colonnade Headed a c
-> (content -> m b) -> (c -> m b)
-> m b -> m b
headerMonadic (Colonnade v) g = headerMonadic (Colonnade v) g =
fmap (mconcat . Vector.toList) $ Vector.mapM (g . getHeaded . oneColonnadeHead) v fmap (mconcat . Vector.toList) $ Vector.mapM (g . getHeaded . oneColonnadeHead) v
headerMonadicGeneral_ :: headerMonadicGeneral_ ::
(Monad m, Foldable h) (Monad m, Foldable h)
=> Colonnade h content a => Colonnade h a c
-> (content -> m b) -> (c -> m b)
-> m () -> m ()
headerMonadicGeneral_ (Colonnade v) g = headerMonadicGeneral_ (Colonnade v) g =
Vector.mapM_ (mapM_ g . oneColonnadeHead) v Vector.mapM_ (mapM_ g . oneColonnadeHead) v
headerMonoidalGeneral :: headerMonoidalGeneral ::
(Monoid m, Foldable h) (Monoid m, Foldable h)
=> Colonnade h c a => Colonnade h a c
-> (c -> m) -> (c -> m)
-> m -> m
headerMonoidalGeneral (Colonnade v) g = headerMonoidalGeneral (Colonnade v) g =
foldMap (foldMap g . oneColonnadeHead) v 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_ :: headerMonadic_ ::
(Monad m) (Monad m)
=> Colonnade Headed content a => Colonnade Headed a c
-> (content -> m b) -> (c -> m b)
-> m () -> m ()
headerMonadic_ (Colonnade v) g = Vector.mapM_ (g . getHeaded . oneColonnadeHead) v 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 :: (Foldable t, Monoid b, Monad m) => (a -> m b) -> t a -> m b
foldlMapM f = foldlM (\b a -> fmap (mappend b) (f a)) mempty foldlMapM f = foldlM (\b a -> fmap (mappend b) (f a)) mempty

View File

@ -1,14 +1,30 @@
{-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveFoldable #-} {-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# OPTIONS_HADDOCK not-home #-} {-# OPTIONS_HADDOCK not-home #-}
{-# OPTIONS_GHC -Wall -fno-warn-unused-imports -fno-warn-unticked-promoted-constructors -Werror #-}
module Colonnade.Internal module Colonnade.Internal
( Colonnade(..) ( -- * Colonnade
Colonnade(..)
, OneColonnade(..) , OneColonnade(..)
, Headed(..) , Headed(..)
, Headless(..) , Headless(..)
-- * Cornice
, Cornice(..)
, AnnotatedCornice(..)
, OneCornice(..)
, Pillar(..)
, ToEmptyCornice(..)
, Fascia(..)
-- * Sizing
, Sized(..)
, MutableSizedColonnade(..)
, MutableSizedCornice(..)
) where ) where
import Data.Vector (Vector) import Data.Vector (Vector)
@ -17,14 +33,20 @@ import Data.Functor.Contravariant.Divisible (Divisible(..))
import Control.Exception (Exception) import Control.Exception (Exception)
import Data.Typeable (Typeable) import Data.Typeable (Typeable)
import Data.Profunctor (Profunctor(..)) import Data.Profunctor (Profunctor(..))
import Data.Semigroup (Semigroup)
import Data.List.NonEmpty (NonEmpty((:|)))
import Data.Foldable (toList)
import qualified Data.Vector.Unboxed.Mutable as MVU
import qualified Data.Semigroup as Semigroup
import qualified Data.Vector as Vector import qualified Data.Vector as Vector
import qualified Data.Vector.Generic as VG
-- | As the first argument to the 'Colonnade' type -- | As the first argument to the 'Colonnade' type
-- constructor, this indictates that the columnar encoding has -- constructor, this indictates that the columnar encoding has
-- a header. This type is isomorphic to 'Identity' but is -- a header. This type is isomorphic to 'Identity' but is
-- given a new name to clarify its intent: -- given a new name to clarify its intent:
-- --
-- > example :: Colonnade Headed Text Foo -- > example :: Colonnade Headed Foo Text
-- --
-- The term @example@ represents a columnar encoding of @Foo@ -- The term @example@ represents a columnar encoding of @Foo@
-- in which the columns have headings. -- in which the columns have headings.
@ -36,13 +58,18 @@ newtype Headed a = Headed { getHeaded :: a }
-- a header. This type is isomorphic to 'Proxy' but is -- a header. This type is isomorphic to 'Proxy' but is
-- given a new name to clarify its intent: -- given a new name to clarify its intent:
-- --
-- > example :: Colonnade Headless Text Foo -- > example :: Colonnade Headless Foo Text
-- --
-- The term @example@ represents a columnar encoding of @Foo@ -- The term @example@ represents a columnar encoding of @Foo@
-- in which the columns do not have headings. -- in which the columns do not have headings.
data Headless a = Headless data Headless a = Headless
deriving (Eq,Ord,Functor,Show,Read,Foldable) deriving (Eq,Ord,Functor,Show,Read,Foldable)
data Sized f a = Sized
{ sizedSize :: {-# UNPACK #-} !Int
, sizedContent :: !(f a)
} deriving (Functor, Foldable)
instance Contravariant Headless where instance Contravariant Headless where
contramap _ Headless = Headless contramap _ Headless = Headless
@ -66,13 +93,13 @@ instance Functor h => Profunctor (OneColonnade h) where
-- that represent HTML with element attributes are provided that serve -- that represent HTML with element attributes are provided that serve
-- as the content type. Presented more visually: -- as the content type. Presented more visually:
-- --
-- > +---- Content (Text, ByteString, Html, etc.) -- > +---- Value consumed to build a row
-- > | -- > |
-- > v -- > v
-- > Colonnade h c a -- > Colonnade h a c
-- > ^ ^ -- > ^ ^
-- > | | -- > | |
-- > | +-- Value consumed to build a row -- > | +-- Content (Text, ByteString, Html, etc.)
-- > | -- > |
-- > +------ Headedness (Headed or Headless) -- > +------ Headedness (Headed or Headless)
-- --
@ -89,6 +116,82 @@ newtype Colonnade h a c = Colonnade
instance Functor h => Profunctor (Colonnade h) where instance Functor h => Profunctor (Colonnade h) where
rmap = fmap rmap = fmap
lmap f (Colonnade v) = Colonnade lmap f (Colonnade v) = Colonnade (Vector.map (lmap f) v)
(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))
data MutableSizedColonnade s h a c = MutableSizedColonnade
{ mutableSizedColonnadeColumns :: {-# UNPACK #-} !(Vector (OneColonnade h a c))
, mutableSizedColonnadeSizes :: {-# UNPACK #-} !(MVU.STVector s Int)
}
-- | 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 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)
}
data Cornice (p :: Pillar) a c where
CorniceBase :: !(Colonnade Headed a c) -> Cornice Base a c
CorniceCap :: {-# UNPACK #-} !(Vector (OneCornice Cornice p a c)) -> Cornice (Cap p) a c
instance Semigroup (Cornice 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 p a c) where
mempty = toEmptyCornice
mappend = (Semigroup.<>)
mconcat xs1 = case xs1 of
[] -> toEmptyCornice
x : xs2 -> Semigroup.sconcat (x :| xs2)
getCorniceBase :: Cornice Base a c -> Colonnade Headed a c
getCorniceBase (CorniceBase c) = c
getCorniceCap :: Cornice (Cap p) a c -> Vector (OneCornice Cornice p a c)
getCorniceCap (CorniceCap c) = c
data AnnotatedCornice (p :: Pillar) a c where
AnnotatedCorniceBase :: !(Colonnade (Sized Headed) a c) -> AnnotatedCornice Base a c
AnnotatedCorniceCap ::
!(Maybe Int)
-> {-# UNPACK #-} !(Vector (OneCornice AnnotatedCornice p a c))
-> AnnotatedCornice (Cap p) a c
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 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

View File

@ -15,7 +15,7 @@
# resolver: # resolver:
# name: custom-snapshot # name: custom-snapshot
# location: "./custom-snapshot.yaml" # location: "./custom-snapshot.yaml"
resolver: lts-7.18 resolver: lts-8.0
# User packages to be built. # User packages to be built.
# Various formats can be used as shown in the example below. # Various formats can be used as shown in the example below.