Frames-0.1.2.1: src/Frames/Rec.hs
{-# LANGUAGE ConstraintKinds,
DataKinds,
EmptyCase,
FlexibleContexts,
FlexibleInstances,
FunctionalDependencies,
KindSignatures,
GADTs,
MultiParamTypeClasses,
PatternSynonyms,
PolyKinds,
ScopedTypeVariables,
TypeFamilies,
TypeOperators,
UndecidableInstances #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Frames.Rec where
import Data.Proxy
import Data.Vinyl (recordToList, rmap, reifyConstraint, Dict(..), Rec)
import Data.Vinyl.TypeLevel (RecAll)
import Data.Vinyl.Functor (Identity(..), Const(..), Compose(..), (:.))
import Frames.Col
import Frames.RecF
-- | A record with unadorned values. This is @Vinyl@'s 'Rec'
-- 'Identity'. We give this type a name as it is used pervasively for
-- records in 'Frames'.
type Record = Rec Identity
-- | A @cons@ function for building 'Record' values.
(&:) :: a -> Record rs -> Record (s :-> a ': rs)
x &: xs = frameCons (Identity x) xs
infixr 5 &:
type family RecordColumns t where
RecordColumns (Record ts) = ts
-- | Separate the first element of a 'Record' from the rest of the row.
recUncons :: Record (s :-> a ': rs) -> (a, Record rs)
recUncons (Identity x :& xs) = (x, xs)
recUncons x = case x of
-- | Undistribute 'Maybe' from a 'Rec' 'Maybe'. This is just a
-- specific usage of 'rtraverse', but it is quite common.
recMaybe :: Rec Maybe cs -> Maybe (Record cs)
recMaybe = rtraverse (fmap Identity)
{-# INLINE recMaybe #-}
-- | Show each field of a 'Record' /without/ its column name.
showFields :: (RecAll Identity (UnColumn ts) Show, AsVinyl ts)
=> Record ts -> [String]
showFields = recordToList . rmap aux . reifyConstraint p . toVinyl
where p = Proxy :: Proxy Show
aux :: (Dict Show :. Identity) a -> Const String a
aux (Compose (Dict x)) = Const (show x)
{-# INLINABLE showFields #-}