-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Scalable anonymous records -- -- The large-anon package provides support for anonymous records -- in Haskell, with a focus on compile-time (and run-time) scalability. @package large-anon @version 0.2 -- | Restore "regular" environment when using RebindableSyntax -- -- The RebindableSyntax extension is currently required when -- using OverloadedRecordUpdate, but when using this extension, -- a number of functions are suddenly no longer in scope that normally -- are. This module restores those functions to their standard -- definition. module Data.Record.Anon.Overloading app :: ArrowApply a => a (a b c, b) c -- | Lift a function to an arrow. arr :: Arrow a => (b -> c) -> a b c -- | Send the first component of the input through the argument arrow, and -- copy the rest unchanged to the output. first :: Arrow a => a b c -> a (b, d) (c, d) loop :: ArrowLoop a => a (b, d) (c, d) -> a b c -- | Left-to-right composition (>>>) :: forall {k} cat (a :: k) (b :: k) (c :: k). Category cat => cat a b -> cat b c -> cat a c infixr 1 >>> -- | Fanin: Split the input between the two argument arrows and merge their -- outputs. -- -- The default definition may be overridden with a more efficient version -- if desired. (|||) :: ArrowChoice a => a b d -> a c d -> a (Either b c) d infixr 2 ||| fromString :: IsString a => String -> a fromLabel :: IsLabel x a => a -- | Selector function to extract the field from the record. getField :: HasField x r a => r -> a ifThenElse :: Bool -> a -> a -> a setField :: forall x r a. HasField x r a => r -> a -> r -- | Supporting definitions used by both the simple and the advanced -- interface -- -- To use the anonymous records library, you will want to use either the -- simple interface in Data.Record.Anon.Simple or the advanced -- interface in Data.Record.Anon.Advanced. This module -- provides definitions that are used by both. Moreover, unlike -- .Simple and .Advanced, this module is designed to be -- imported unqualified. A typical import section will therefore look -- something like -- --
-- import Data.Record.Anon -- import Data.Record.Anon.Simple (Record) -- import qualified Data.Record.Anon.Simple as Anon ---- -- In addition, since the classes and type families defined here as -- handled by the plugin, you will also want to enable that: -- --
-- {-# OPTIONS_GHC -fplugin=Data.Record.Anon.Plugin #-}
--
module Data.Record.Anon
pattern (:=) :: () => a -> b -> Pair a b
-- | Row: type-level list of field names and corresponding field types
type Row k = [Pair Symbol k]
-- | Merge two rows
--
-- See merge for detailed discussion.
type family Merge :: Row k -> Row k -> Row k
-- | Require that c x holds for every (n := x) in
-- r.
class AllFields (r :: Row k) (c :: k -> Constraint)
-- | Require that all field names in r are known
class KnownFields (r :: Row k)
-- | Subrecords
--
-- If SubRow r r' holds, we can project (or create a lens)
-- r to r'. See project for detailed discussion.
class SubRow (r :: Row k) (r' :: Row k)
-- | Specialized form of HasField
--
-- RowHasField n r a holds if there is an (n := a) in
-- r.
class RowHasField (n :: Symbol) (r :: Row k) (a :: k) | n r -> a
-- | Proxy for a field name, with IsLabel instance
--
-- The IsLabel instance makes it possible to write
--
-- -- #foo ---- -- to mean -- --
-- Field (Proxy @"foo") --data Field n -- | Symbol (type-level string) with compile-time computed hash -- -- Instances are computed on the fly by the plugin. class KnownHash (s :: Symbol) hashVal :: forall proxy. KnownHash s => proxy s -> Int -- | Type-level metadata -- --
-- FieldTypes Maybe [ "a" := Int, "b" := Bool ]
-- == [ '("a", Maybe Int), '("b", Maybe Bool) ]
--
type family FieldTypes (f :: k -> Type) (r :: Row k) :: [(Symbol, Type)]
-- | Like FieldTypes, but for the simple API (no functor argument)
--
--
-- SimpleFieldTypes [ "a" := Int, "b" := Bool ]
-- == [ '("a", Int), '("b", Bool) ]
--
type family SimpleFieldTypes (r :: Row Type) :: [(Symbol, Type)]
-- | Existential type ("there exists an x such that f x")
data Some (f :: k -> Type)
[Some] :: forall k (f :: k -> Type) (x :: k). f x -> Some f
-- | Evidence of some constraint c
--
-- This is like Dict, but without the functor argument.
data Reflected c
[Reflected] :: c => Reflected c
-- | Lifted product of functors.
data Product (f :: k -> Type) (g :: k -> Type) (a :: k)
Pair :: f a -> g a -> Product (f :: k -> Type) (g :: k -> Type) (a :: k)
-- | Proxy is a type that holds no data, but has a phantom parameter
-- of arbitrary type (or even kind). Its use is to provide type
-- information, even though there is no value available of that type (or
-- it may be too costly to create one).
--
-- Historically, Proxy :: Proxy a is a safer
-- alternative to the undefined :: a idiom.
--
-- -- >>> Proxy :: Proxy (Void, Int -> Int) -- Proxy ---- -- Proxy can even hold types of higher kinds, -- --
-- >>> Proxy :: Proxy Either -- Proxy ---- --
-- >>> Proxy :: Proxy Functor -- Proxy ---- --
-- >>> Proxy :: Proxy complicatedStructure -- Proxy --data Proxy (t :: k) Proxy :: Proxy (t :: k) -- | Composition of functors. -- -- Like Compose, but kind-polymorphic and with a shorter name. newtype ( (f :: l -> Type) :.: (g :: k -> l) ) (p :: k) Comp :: f (g p) -> (:.:) (f :: l -> Type) (g :: k -> l) (p :: k) infixr 7 :.: -- | The identity type functor. -- -- Like Identity, but with a shorter name. newtype I a I :: a -> I a -- | The constant type functor. -- -- Like Constant, but kind-polymorphic in its second argument and -- with a shorter name. newtype K a (b :: k) K :: a -> K a (b :: k) -- | Extract the contents of an I value. unI :: I a -> a -- | Lifted functions. newtype ( (f :: k -> Type) -.-> (g :: k -> Type) ) (a :: k) Fn :: (f a -> g a) -> (-.->) (f :: k -> Type) (g :: k -> Type) (a :: k) [apFn] :: (-.->) (f :: k -> Type) (g :: k -> Type) (a :: k) -> f a -> g a infixr 1 -.-> -- | Composition of constraints. -- -- Note that the result of the composition must be a constraint, and -- therefore, in Compose f g, the kind of f is -- k -> Constraint. The kind of g, however, -- is l -> k and can thus be a normal type constructor. -- -- A typical use case is in connection with All on an NP or -- an NS. For example, in order to denote that all elements on an -- NP f xs satisfy Show, we can say All -- (Compose Show f) xs. class f g x => Compose (f :: k -> Constraint) (g :: k1 -> k) (x :: k1) infixr 9 `Compose` -- | An explicit dictionary carrying evidence of a class constraint. -- -- The constraint parameter is separated into a second argument so that -- Dict c is of the correct kind to be used directly as a -- parameter to e.g. NP. data Dict (c :: k -> Constraint) (a :: k) [Dict] :: forall {k} (c :: k -> Constraint) (a :: k). c a => Dict c a -- | Constraint representing the fact that the field x can be get -- and set on the record type r and has field type a. -- This constraint will be solved automatically, but manual instances may -- be provided as well. -- -- The function should satisfy the invariant: -- --
-- uncurry ($) (hasField @x r) == r --class HasField (x :: k) r a | x r -> a -- | Function to get and set a field in a record. hasField :: HasField x r a => r -> (a -> r, a) -- | This class gives the string associated with a type-level symbol. There -- are instances of the class for every concrete literal: "hello", etc. class KnownSymbol (n :: Symbol) -- | Advanced interface (with a functor argument) -- -- See Data.Record.Anon.Simple for the simple interface. You will -- probably also want to import Data.Record.Anon. -- -- Intended for qualified import. -- --
-- import Data.Record.Anon -- import Data.Record.Anon.Advanced (Record) -- import qualified Data.Record.Anon.Advanced as Anon --module Data.Record.Anon.Advanced -- | Anonymous record data Record (f :: k -> Type) (r :: Row k) -- | Empty record empty :: Record f '[] -- | Insert new field -- --
-- >>> :{
-- example :: Record Maybe [ "a" := Bool, "b" := Int ]
-- example =
-- insert #a (Just True)
-- $ insert #b Nothing
-- $ empty
-- :}
--
--
-- Instead of using insert and empty, you can also write
-- this as
--
--
-- example = ANON_F {
-- a = Just True
-- , b = Nothing
-- }
--
insert :: Field n -> f a -> Record f r -> Record f ((n := a) : r)
-- | Applicative insert
--
-- This is a simple wrapper around insert, but can be quite useful
-- when constructing records. Consider code like
--
--
-- >>> :{
-- example :: Applicative m => m a -> m b -> m (a, b)
-- example ma mb = (,) <$> ma <*> mb
-- :}
--
--
-- We cannot really extend this to the world of named records, but we
-- can do something comparable using anonymous records:
--
--
-- >>> :{
-- example ::
-- Applicative m
-- => m (f a) -> m (f b) -> m (Record f [ "a" := a, "b" := b ])
-- example ma mb =
-- insertA #a ma
-- $ insertA #b mb
-- $ Prelude.pure empty
-- :}
--
--
-- As for regular insert, this example too can instead be written
-- using ANON_F and sequenceA (or sequenceA').
--
--
-- example ma mb = sequenceA $ ANON_F {
-- a = Comp ma
-- , b = Comp mb
-- }
--
insertA :: Applicative m => Field n -> m (f a) -> m (Record f r) -> m (Record f ((n := a) : r))
-- | Apply all pending changes to the record
--
-- Updates to a record are stored in a hashtable. As this hashtable
-- grows, record field access and update will become more expensive.
-- Applying the updates, resulting in a flat vector, is an O(n)
-- operation. This will happen automatically whenever another
-- O(n) operation is applied (for example, mapping a function
-- over the record). However, occassionally it is useful to explicitly
-- apply these changes, for example after constructing a record or
-- updating a lot of fields.
applyPending :: Record f r -> Record f r
-- | Get field from the record
--
-- This is just a wrapper around getField.
--
--
-- >>> :{
-- example :: Record Maybe [ "a" := Bool, "b" := Int ] -> Maybe Bool
-- example r = get #a r
-- :}
--
--
-- If using record-dot-preprocessor, you can also write this
-- example as
--
-- -- example r = r.a ---- -- If the field does not exist, you will get a type error about an -- unsolvable RowHasField constraint: -- --
-- >>> :{
-- absentField :: Record Maybe [ "a" := Bool, "b" := Int ] -> Maybe Char
-- absentField r = get #c r
-- :}
-- ...
-- ...No instance for (RowHasField "c"...
-- ...
--
--
-- Type mismatches will result in regular type errors:
--
--
-- >>> :{
-- wrongType :: Record Maybe [ "a" := Bool, "b" := Int ] -> Maybe Char
-- wrongType r = get #a r
-- :}
-- ...
-- ...Couldn't match...Char...Bool...
-- ...
--
--
-- When part of the record is not known, it might not be possible to
-- resolve a HasField constraint until later. For example, in
--
--
-- >>> :{
-- unknownField :: Record Maybe [ x := Bool, "b" := Int ] -> Maybe Int
-- unknownField r = get #b r
-- :}
-- ...
-- ...No instance for (RowHasField "b"...
-- ...
--
--
-- (Note that x here is a variable, not a string.) It is
-- important that the constraint remains unsolved in this example,
-- because if x == "b", the first field would shadow the second,
-- and the result type should be Maybe Bool instead of Maybe
-- Int.
get :: RowHasField n r a => Field n -> Record f r -> f a
-- | Update field in the record
--
-- This is just a wrapper around setField.
--
--
-- >>> :{
-- example ::
-- Record Maybe [ "a" := Bool, "b" := Int ]
-- -> Record Maybe [ "a" := Bool, "b" := Int ]
-- example r = set #a (Just False) r
-- :}
--
--
-- If using record-dot-preprocessor, can also write this example
-- as
--
--
-- example r = r{a = Just False}
--
set :: RowHasField n r a => Field n -> f a -> Record f r -> Record f r
-- | Project from one record to another
--
-- Both the source record and the target record must be fully known.
--
-- The target record can omit fields from the source record, as well as
-- rearrange them:
--
--
-- >>> :{
-- example ::
-- Record f [ "a" := Char, "b" := Int, "c" := Bool ]
-- -> Record f [ "c" := Bool, "a" := Char ]
-- example = project
-- :}
--
--
-- Of course, it is not possible to add fields:
--
--
-- >>> :{
-- example ::
-- Record f [ "c" := Bool, "a" := Char ]
-- -> Record f [ "a" := Char, "b" := Int, "c" := Bool ]
-- example = project
-- :}
-- ...
-- ...No instance for (SubRow...
-- ...
--
--
-- Type inference will work through projections: field types are unified
-- based on their name:
--
--
-- >>> :{
-- example ::
-- Record f [ "a" := Char, "b" := Int, "c" := Bool ]
-- -> Record f [ "c" := _, "a" := Char ]
-- example = project
-- :}
-- ...
-- ...Found type wildcard...Bool...
-- ...
--
--
-- As we saw in merge, project can also flatten
-- Merged rows.
project :: SubRow r r' => Record f r -> Record f r'
-- | Inject smaller record into larger record
--
-- This is just the lens setter.
inject :: SubRow r r' => Record f r' -> Record f r -> Record f r
-- | Lens from one record to another
--
-- See project for examples (project is just the lens
-- getter, without the setter).
lens :: SubRow r r' => Record f r -> (Record f r', Record f r' -> Record f r)
-- | Merge two records
--
-- The Merge type family does not reduce:
--
--
-- >>> :{
-- example :: Record Maybe (Merge '[ "a" := Bool ] '[])
-- example = merge (insert #a (Just True) empty) empty
-- :}
--
--
-- If you want to flatten the row after merging, you can use
-- project:
--
--
-- >>> :{
-- example :: Record Maybe '[ "a" := Bool ]
-- example = project $ merge (insert #a (Just True) empty) empty
-- :}
--
--
-- HasField constraints can be resolved for merged records,
-- subject to the same condition discussed in get: all fields in
-- the record must be known up to the requested field (in case of
-- shadowing). So the record may be fully known:
--
--
-- >>> :{
-- example :: Record f (Merge '[ "a" := Bool ] '[ "b" := Char ]) -> f Char
-- example r = get #b r
-- :}
--
--
-- but it doesn't have to be:
--
--
-- >>> :{
-- example :: Record I (Merge '[ "a" := Bool ] r) -> I Bool
-- example = get #a
-- :}
--
--
-- However, just like in the case of unknown fields (see example in
-- get), if earlier parts in the record are unknown we get type
-- error:
--
--
-- >>> :{
-- example :: Record I (Merge r '[ "b" := Char ]) -> I Char
-- example r = get #b r
-- :}
-- ...
-- ...No instance for (RowHasField "b"...
-- ...
--
merge :: Record f r -> Record f r' -> Record f (Merge r r')
-- | Analogue to fmap
map :: (forall x. f x -> g x) -> Record f r -> Record g r
-- | Constrained form of map
cmap :: AllFields r c => Proxy c -> (forall x. c x => f x -> g x) -> Record f r -> Record g r
-- | Analogue of pure
pure :: KnownFields r => (forall x. f x) -> Record f r
-- | Constrained form of pure
cpure :: AllFields r c => Proxy c -> (forall x. c x => f x) -> Record f r
-- | Analogue of <*>
ap :: Record (f -.-> g) r -> Record f r -> Record g r
-- | Analogue of toList
collapse :: Record (K a) r -> [a]
-- | Like collapse, but also include field names
toList :: KnownFields r => Record (K a) r -> [(String, a)]
-- | Analogue to mapM
mapM :: Applicative m => (forall x. f x -> m (g x)) -> Record f r -> m (Record g r)
-- | Constrained form of cmap
cmapM :: (Applicative m, AllFields r c) => Proxy c -> (forall x. c x => f x -> m (g x)) -> Record f r -> m (Record g r)
-- | Analogue of sequenceA
sequenceA :: Applicative m => Record (m :.: f) r -> m (Record f r)
-- | Simplified form of sequenceA
sequenceA' :: Applicative m => Record m r -> m (Record I r)
-- | Analogue of zip
zip :: Record f r -> Record g r -> Record (Product f g) r
-- | Analogue of zipWith
zipWith :: (forall x. f x -> g x -> h x) -> Record f r -> Record g r -> Record h r
-- | Analogue of zipWithM
zipWithM :: Applicative m => (forall x. f x -> g x -> m (h x)) -> Record f r -> Record g r -> m (Record h r)
-- | Constrained form of zipWith
czipWith :: AllFields r c => Proxy c -> (forall x. c x => f x -> g x -> h x) -> Record f r -> Record g r -> Record h r
-- | Constrained form of zipWithM
czipWithM :: (Applicative m, AllFields r c) => Proxy c -> (forall x. c x => f x -> g x -> m (h x)) -> Record f r -> Record g r -> m (Record h r)
-- | Record of dictionaries
--
-- This reifies an AllFields constraint as a record.
--
-- Inverse to reflectKnownFields.
reifyAllFields :: AllFields r c => proxy c -> Record (Dict c) r
-- | Establish AllFields from a record of dictionaries
--
-- Inverse to reifyKnownFields.
reflectAllFields :: Record (Dict c) r -> Reflected (AllFields r c)
-- | Record of field names
--
-- This reifies a KnownFields constraint as a record.
--
-- Inverse to reflectAllFields.
reifyKnownFields :: KnownFields r => proxy r -> Record (K String) r
-- | Establish KnownFields from a record of field names
--
-- Inverse to reifyAllFields.
reflectKnownFields :: Record (K String) r -> Reflected (KnownFields r)
-- | InRow r a is evidence that there exists some n s.t.
-- (n := a) in r.
data InRow (r :: Row k) (a :: k)
[InRow] :: forall k (n :: Symbol) (r :: Row k) (a :: k). (KnownSymbol n, RowHasField n r a) => Proxy n -> InRow r a
-- | Record over r' with evidence that every field is in
-- r.
--
-- This reifies a SubRow constraint.
--
-- Inverse to reflectSubRow.
reifySubRow :: (KnownFields r', SubRow r r') => Record (InRow r) r'
-- | Establish SubRow from a record of evidence.
--
-- Inverse to reifySubRow.
reflectSubRow :: Record (InRow r) r' -> Reflected (SubRow r r')
-- | Discovered row variable
--
-- See someRecord for detailed discussion.
data SomeRecord (f :: k -> Type)
[SomeRecord] :: forall k (r :: Row k) (f :: k -> Type). KnownFields r => Record (Product (InRow r) f) r -> SomeRecord f
-- | Construct record with existentially quantified row variable
--
-- Existentially quantified records arise for example when parsing JSON
-- values as records. Pattern matching on the result of someRecord
-- brings into scope an existentially quantified row variable r,
-- along with a record over r; every field in record contains
-- the value specified, as well as evidence that that that field is
-- indeed an element of r.
--
-- For such a record to be useful, you will probably want to prove
-- additional constraints AllFields r c; you can do this using
-- reflectAllFields, provided that you carefully pick your
-- f such that you can define a function
--
-- -- fieldSatisfiesC :: forall c. f x -> Dict c x ---- -- for every c you want to prove. -- -- It is also possible to do a runtime check to see if the existential -- row r can be projected to some concrete known row -- r'. To do this, construct a record of evidence with type -- --
-- Record (InRow r) r' ---- -- and then call reflectSubRow. To construct this record of -- evidence you will need to do a runtime type check to verify that the -- types of the fields in concrete row match the types of the -- corresponding fields in the inferred row (the inferred row may contain -- fields that are not present in the concrete row, of course). An -- obvious candidate for doing this is Typeable, but for specific -- applications (with specific subsets of types of interest) other -- choices may be possible also. -- -- The large-anon test suite contains examples of doing both of -- these things; see Test.Infra.DynRecord.Simple (or -- Test.Infra.DynRecord.Advanced for rows over kind other than -- Type) for examples of proving additional constraints, and -- Test.Infra.Discovery for an example of how you could do a -- projection check. someRecord :: [(String, Some f)] -> SomeRecord f -- | Introduce type variable for a row -- -- This can be used in conjunction with letInsertAs: -- --
-- >>> :{
-- example :: Record I '[ "a" := Int, "b" := Char, "c" := Bool ]
-- example = letRecordT $ \p -> castEqual $
-- letInsertAs p #c (I True) empty $ \xs02 ->
-- letInsertAs p #b (I 'X' ) xs02 $ \xs01 ->
-- letInsertAs p #a (I 1 ) xs01 $ \xs00 ->
-- castEqual xs00
-- :}
--
letRecordT :: forall r f. (forall r'. Let r' r => Proxy r' -> Record f r) -> Record f r
-- | Insert field into a record and introduce type variable for the result
letInsertAs :: forall r r' f n a. Proxy r -> Field n -> f a -> Record f r' -> (forall r''. Let r'' ((n := a) : r') => Record f r'' -> Record f r) -> Record f r
castEqual :: Equal a b => a -> b
-- | Simple interface (without a functor argument)
--
-- See Data.Record.Anon.Advanced for the advanced interface. You
-- will probably also want to import Data.Record.Anon.
--
-- Intended for qualified import.
--
-- -- import Data.Record.Anon -- import Data.Record.Anon.Simple (Record) -- import qualified Data.Record.Anon.Simple as Anon --module Data.Record.Anon.Simple -- | Anonymous record -- -- A Record r has a field n of type x for -- every (n := x) in r. -- -- To construct a Record, use insert and empty, or -- use the ANON syntax. See insert for examples. -- -- To access fields of the record, either use the HasField -- instances (possibly using the record-dot-preprocessor), or -- using get and set. -- -- Remember to enable the plugin when working with anonymous records: -- --
-- {-# OPTIONS_GHC -fplugin=Data.Record.Anon.Plugin #-}
--
--
-- NOTE: For some applications it is useful to have an additional functor
-- parameter f, so that every field has type f x
-- instead. See Data.Record.Anon.Advanced.
data Record r
-- | Empty record
empty :: Record '[]
-- | Insert new field
--
--
-- >>> :{
-- example :: Record [ "a" := Bool, "b" := Int ]
-- example =
-- insert #a True
-- $ insert #b 1
-- $ empty
-- :}
--
--
-- Instead of using insert and empty, you can also write
-- this as
--
--
-- example = ANON {
-- a = True
-- , b = 1
-- }
--
insert :: Field n -> a -> Record r -> Record ((n := a) : r)
-- | Applicative insert
--
-- This is a simple wrapper around insert, but can be quite useful
-- when constructing records. Consider code like
--
--
-- >>> :{
-- example :: Applicative m => m a -> m b -> m (a, b)
-- example ma mb = (,) <$> ma <*> mb
-- :}
--
--
-- We cannot really extend this to the world of named records, but we
-- can do something comparable using anonymous records:
--
--
-- >>> :{
-- example :: Applicative m => m a -> m b -> m (Record [ "a" := a, "b" := b ])
-- example ma mb =
-- insertA #a ma
-- $ insertA #b mb
-- $ pure empty
-- :}
--
--
-- However, it may be more convenient to use the advanced API for this.
-- See insertA.
insertA :: Applicative m => Field n -> m a -> m (Record r) -> m (Record ((n := a) : r))
-- | Apply all pending changes to the record
--
-- Updates to a record are stored in a hashtable. As this hashtable
-- grows, record field access and update will become more expensive.
-- Applying the updates, resulting in a flat vector, is an O(n)
-- operation. This will happen automatically whenever another
-- O(n) operation is applied (for example, mapping a function
-- over the record). However, occassionally it is useful to explicitly
-- apply these changes, for example after constructing a record or
-- updating a lot of fields.
applyPending :: Record r -> Record r
-- | Get field from the record
--
-- This is just a wrapper around getField.
--
--
-- >>> :{
-- example :: Record [ "a" := Bool, "b" := Int ] -> Bool
-- example r = get #a r
-- :}
--
--
-- If using record-dot-preprocessor, you can also write this
-- example as
--
-- -- example r = r.a ---- -- See get for additional discussion. get :: RowHasField n r a => Field n -> Record r -> a -- | Update field in the record -- -- This is just a wrapper around setField. -- --
-- >>> :{
-- example ::
-- Record [ "a" := Bool, "b" := Int ]
-- -> Record [ "a" := Bool, "b" := Int ]
-- example r = set #a False r
-- :}
--
--
-- If using record-dot-preprocessor, can also write this example
-- as
--
--
-- example r = r{a = False}
--
set :: RowHasField n r a => Field n -> a -> Record r -> Record r
-- | Project from one record to another
--
-- Both the source record and the target record must be fully known.
--
-- The target record can omit fields from the source record, as well as
-- rearrange them:
--
--
-- >>> :{
-- example ::
-- Record [ "a" := Char, "b" := Int, "c" := Bool ]
-- -> Record [ "c" := Bool, "a" := Char ]
-- example = project
-- :}
--
--
-- As we saw in merge, project can also flatten
-- Merged rows. See project for additional discussion.
project :: SubRow r r' => Record r -> Record r'
-- | Inject smaller record into larger record
--
-- This is just the lens setter.
inject :: SubRow r r' => Record r' -> Record r -> Record r
-- | Lens from one record to another
--
-- See project for examples (project is just the lens
-- getter, without the setter).
lens :: SubRow r r' => Record r -> (Record r', Record r' -> Record r)
-- | Merge two records
--
-- The Merge type family does not reduce:
--
--
-- >>> :{
-- example :: Record (Merge '[ "a" := Bool ] '[])
-- example = merge (insert #a True empty) empty
-- :}
--
--
-- If you want to flatten the row after merging, you can use
-- project:
--
--
-- >>> :{
-- example :: Record '[ "a" := Bool ]
-- example = project $ merge (insert #a True empty) empty
-- :}
--
--
-- See merge for additional discussion.
merge :: Record r -> Record r' -> Record (Merge r r')
-- | Move from the simple to the advanced interface
--
-- This is an O(1) operation.
toAdvanced :: Record r -> Record I r
-- | Move from the advanced to the simple interface
--
-- This is an O(1) operation.
fromAdvanced :: Record I r -> Record r
-- | Sequence all actions
sequenceA :: Applicative m => Record m r -> m (Record r)
-- | Introduce type variable for a row
--
-- This can be used in conjunction with letInsertAs:
--
--
-- >>> :{
-- example :: Record '[ "a" := Int, "b" := Char, "c" := Bool ]
-- example = letRecordT $ \p -> castEqual $
-- letInsertAs p #c True empty $ \xs02 ->
-- letInsertAs p #b 'X' xs02 $ \xs01 ->
-- letInsertAs p #a 1 xs01 $ \xs00 ->
-- castEqual xs00
-- :}
--
letRecordT :: forall r. (forall r'. Let r' r => Proxy r' -> Record r) -> Record r
-- | Insert field into a record and introduce type variable for the result
letInsertAs :: forall r r' n a. Proxy r -> Field n -> a -> Record r' -> (forall r''. Let r'' ((n := a) : r') => Record r'' -> Record r) -> Record r
castEqual :: Equal a b => a -> b