Safe Haskell | None |
---|---|
Language | Haskell2010 |
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
Synopsis
- data Record r
- empty :: Record '[]
- insert :: Field n -> a -> Record r -> Record ((n := a) ': r)
- insertA :: Applicative m => Field n -> m a -> m (Record r) -> m (Record ((n := a) ': r))
- applyPending :: Record r -> Record r
- get :: RowHasField n r a => Field n -> Record r -> a
- set :: RowHasField n r a => Field n -> a -> Record r -> Record r
- project :: SubRow r r' => Record r -> Record r'
- inject :: SubRow r r' => Record r' -> Record r -> Record r
- lens :: SubRow r r' => Record r -> (Record r', Record r' -> Record r)
- merge :: Record r -> Record r' -> Record (Merge r r')
- toAdvanced :: Record r -> Record I r
- fromAdvanced :: Record I r -> Record r
- sequenceA :: Applicative m => Record m r -> m (Record r)
- letRecordT :: forall r. (forall r'. Let r' r => Proxy r' -> Record r) -> Record r
- 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
Documentation
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.
Instances
Construction
insertA :: Applicative m => Field n -> m a -> m (Record r) -> m (Record ((n := a) ': r)) Source #
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
.
applyPending :: Record r -> Record r Source #
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.
Field access
get :: RowHasField n r a => Field n -> Record r -> a Source #
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.
set :: RowHasField n r a => Field n -> a -> Record r -> Record r Source #
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}
Changing rows
project :: SubRow r r' => Record r -> Record r' Source #
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 Merge
d rows.
See project
for additional discussion.
inject :: SubRow r r' => Record r' -> Record r -> Record r Source #
Inject smaller record into larger record
This is just the lens
setter.
merge :: Record r -> Record r' -> Record (Merge r r') Source #
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.
Interop with the advanced API
toAdvanced :: Record r -> Record I r Source #
Move from the simple to the advanced interface
This is an O(1)
operation.
fromAdvanced :: Record I r -> Record r Source #
Move from the advanced to the simple interface
This is an O(1)
operation.
Experimental integration with typelet
The typelet
plugin provides support for type sharing. These functions
can be used to construct records that result in ghc core that is truly
linear in size.
letRecordT :: forall r. (forall r'. Let r' r => Proxy r' -> Record r) -> Record r Source #
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 :}
:: forall r r' n a. Proxy r | Type of the record we are constructing |
-> Field n | New field to be inserted |
-> a | Value of the new field |
-> Record r' | Record constructed so far |
-> (forall r''. Let r'' ((n := a) ': r') => Record r'' -> Record r) | Assign type variable to new partial record, and continue |
-> Record r |
Insert field into a record and introduce type variable for the result