{-# LANGUAGE ConstraintKinds  #-}
{-# LANGUAGE DataKinds        #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedLabels #-}
{-# LANGUAGE PolyKinds        #-}
{-# LANGUAGE RankNTypes       #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators    #-}

-- | 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 (
    Record
    -- * Construction
  , empty
  , insert
  , insertA
  , applyPending
    -- * Field access
  , get
  , set
    -- * Changing rows
  , project
  , inject
  , lens
  , merge
    -- * Combinators
    -- ** " Functor "
  , map
  , cmap
    -- ** " Applicable "
  , pure
  , cpure
  , ap
    -- ** " Foldable "
  , collapse
  , toList
    -- ** " Traversable "
  , mapM
  , cmapM
  , sequenceA
  , sequenceA'
    -- ** Zipping
  , zip
  , zipWith
  , zipWithM
  , czipWith
  , czipWithM
    -- * Constraint reification and reflection
  , reifyAllFields
  , reflectAllFields
  , reifyKnownFields
  , reflectKnownFields
  , A.InRow(..)
  , reifySubRow
  , reflectSubRow
    -- * Existential records
  , A.SomeRecord(..)
  , someRecord
    -- * 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
  , letInsertAs
  ) where

import Prelude hiding (sequenceA, map, mapM, pure, zip, zipWith)

import TypeLet

import Data.Record.Anon

import Data.Record.Anon.Internal.Advanced (Record)
import qualified Data.Record.Anon.Internal.Advanced as A

-- $setup
-- >>> :set -XDataKinds
-- >>> :set -XOverloadedLabels
-- >>> :set -XTypeOperators
-- >>> :set -fplugin=TypeLet -fplugin=Data.Record.Anon.Plugin
-- >>> :set -dppr-cols=200
-- >>> import Prelude hiding (pure)
-- >>> import qualified Prelude
-- >>> import Data.Record.Anon
-- >>> import TypeLet

{-------------------------------------------------------------------------------
  Construction

  Here and elsewhere, we don't just re-export the function, but instead provide
  an alias for it. This means that all user-facing documentation and,
  importantly, all docspec tests, are in public modules.

  Unfortunately, docspec (being ghci-based) cannot take advantage of the source
  plugin, so we cannot give testable examples using ANON_F.
-------------------------------------------------------------------------------}

-- | Empty record
empty :: Record f '[]
empty :: Record f '[]
empty = Record f '[]
forall k (f :: k -> *). Record f '[]
A.empty

-- | 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)
insert :: Field n -> f a -> Record f r -> Record f ((n ':= a) : r)
insert = Field n -> f a -> Record f r -> Record f ((n ':= a) : r)
forall k (f :: k -> *) (r :: Row k) (a :: k) (n :: Symbol).
Field n -> f a -> Record f r -> Record f ((n ':= a) : r)
A.insert

-- | 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))
insertA :: Field n
-> m (f a) -> m (Record f r) -> m (Record f ((n ':= a) : r))
insertA = Field n
-> m (f a) -> m (Record f r) -> m (Record f ((n ':= a) : r))
forall b (m :: * -> *) (n :: Symbol) (f :: b -> *) (a :: b)
       (r :: Row b).
Applicative m =>
Field n
-> m (f a) -> m (Record f r) -> m (Record f ((n ':= a) : r))
A.insertA

-- | 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
applyPending :: Record f r -> Record f r
applyPending = Record f r -> Record f r
forall k (f :: k -> *) (r :: Row k). Record f r -> Record f r
A.applyPending

{-------------------------------------------------------------------------------
  Field access
-------------------------------------------------------------------------------}

-- | 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
get :: Field n -> Record f r -> f a
get = Field n -> Record f r -> f a
forall k (n :: Symbol) (f :: k -> *) (r :: Row k) (a :: k).
RowHasField n r a =>
Field n -> Record f r -> f a
A.get

-- | 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
set :: Field n -> f a -> Record f r -> Record f r
set = Field n -> f a -> Record f r -> Record f r
forall k (n :: Symbol) (f :: k -> *) (r :: Row k) (a :: k).
RowHasField n r a =>
Field n -> f a -> Record f r -> Record f r
A.set

{-------------------------------------------------------------------------------
  Changing rows
-------------------------------------------------------------------------------}

-- | 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 'Merge'd rows.
project :: SubRow r r' => Record f r -> Record f r'
project :: Record f r -> Record f r'
project = Record f r -> Record f r'
forall k (r :: Row k) (r' :: Row k) (f :: k -> *).
SubRow r r' =>
Record f r -> Record f r'
A.project

-- | 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
inject :: Record f r' -> Record f r -> Record f r
inject = Record f r' -> Record f r -> Record f r
forall k (r :: Row k) (r' :: Row k) (f :: k -> *).
SubRow r r' =>
Record f r' -> Record f r -> Record f r
A.inject

-- | 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)
lens :: Record f r -> (Record f r', Record f r' -> Record f r)
lens = Record f r -> (Record f r', Record f r' -> Record f r)
forall k (f :: k -> *) (r :: Row k) (r' :: Row k).
SubRow r r' =>
Record f r -> (Record f r', Record f r' -> Record f r)
A.lens

-- | 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')
merge :: Record f r -> Record f r' -> Record f (Merge r r')
merge = Record f r -> Record f r' -> Record f (Merge r r')
forall k (f :: k -> *) (r :: Row k) (r' :: Row k).
Record f r -> Record f r' -> Record f (Merge r r')
A.merge

{-------------------------------------------------------------------------------
  Combinators
-------------------------------------------------------------------------------}

-- | Analogue to 'Prelude.fmap'
map :: (forall x. f x -> g x) -> Record f r -> Record g r
map :: (forall (x :: k). f x -> g x) -> Record f r -> Record g r
map forall (x :: k). f x -> g x
f = (forall (x :: k). f x -> g x) -> Record f r -> Record g r
forall k (f :: k -> *) (g :: k -> *) (r :: Row k).
(forall (x :: k). f x -> g x) -> Record f r -> Record g r
A.map forall (x :: k). f x -> g x
f

-- | Analogue to 'Prelude.mapM'
mapM :: Applicative m => (forall x. f x -> m (g x)) -> Record f r -> m (Record g r)
mapM :: (forall (x :: k). f x -> m (g x)) -> Record f r -> m (Record g r)
mapM forall (x :: k). f x -> m (g x)
f = (forall (x :: k). f x -> m (g x)) -> Record f r -> m (Record g r)
forall k (m :: * -> *) (f :: k -> *) (g :: k -> *) (r :: Row k).
Applicative m =>
(forall (x :: k). f x -> m (g x)) -> Record f r -> m (Record g r)
A.mapM forall (x :: k). f x -> m (g x)
f

-- | Constrained form of 'map'
cmap ::
     AllFields r c
  => Proxy c -> (forall x. c x => f x -> g x) -> Record f r -> Record g r
cmap :: Proxy c
-> (forall (x :: k). c x => f x -> g x) -> Record f r -> Record g r
cmap Proxy c
p forall (x :: k). c x => f x -> g x
f = Proxy c
-> (forall (x :: k). c x => f x -> g x) -> Record f r -> Record g r
forall k (r :: Row k) (c :: k -> Constraint) (f :: k -> *)
       (g :: k -> *).
AllFields r c =>
Proxy c
-> (forall (x :: k). c x => f x -> g x) -> Record f r -> Record g r
A.cmap Proxy c
p forall (x :: k). c x => f x -> g x
f

-- | 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)
cmapM :: Proxy c
-> (forall (x :: k). c x => f x -> m (g x))
-> Record f r
-> m (Record g r)
cmapM Proxy c
p forall (x :: k). c x => f x -> m (g x)
f = Proxy c
-> (forall (x :: k). c x => f x -> m (g x))
-> Record f r
-> m (Record g r)
forall k (m :: * -> *) (r :: Row k) (c :: k -> Constraint)
       (f :: k -> *) (g :: k -> *).
(Applicative m, AllFields r c) =>
Proxy c
-> (forall (x :: k). c x => f x -> m (g x))
-> Record f r
-> m (Record g r)
A.cmapM Proxy c
p forall (x :: k). c x => f x -> m (g x)
f

-- | Analogue of 'Prelude.pure'
pure :: KnownFields r => (forall x. f x) -> Record f r
pure :: (forall (x :: k). f x) -> Record f r
pure forall (x :: k). f x
f = (forall (x :: k). f x) -> Record f r
forall k (f :: k -> *) (r :: Row k).
KnownFields r =>
(forall (x :: k). f x) -> Record f r
A.pure forall (x :: k). f x
f

-- | Constrained form of 'pure'
cpure :: AllFields r c => Proxy c -> (forall x. c x => f x) -> Record f r
cpure :: Proxy c -> (forall (x :: k). c x => f x) -> Record f r
cpure Proxy c
p forall (x :: k). c x => f x
f = Proxy c -> (forall (x :: k). c x => f x) -> Record f r
forall k (r :: Row k) (f :: k -> *) (c :: k -> Constraint).
AllFields r c =>
Proxy c -> (forall (x :: k). c x => f x) -> Record f r
A.cpure Proxy c
p forall (x :: k). c x => f x
f

-- | Analogue of '<*>'
ap :: Record (f -.-> g) r -> Record f r -> Record g r
ap :: Record (f -.-> g) r -> Record f r -> Record g r
ap = Record (f -.-> g) r -> Record f r -> Record g r
forall k (f :: k -> *) (g :: k -> *) (r :: Row k).
Record (f -.-> g) r -> Record f r -> Record g r
A.ap

-- | Analogue of 'Data.Foldable.toList'
collapse :: Record (K a) r -> [a]
collapse :: Record (K a) r -> [a]
collapse = Record (K a) r -> [a]
forall k a (r :: Row k). Record (K a) r -> [a]
A.collapse

-- | Like 'collapse', but also include field names
toList :: KnownFields r => Record (K a) r -> [(String, a)]
toList :: Record (K a) r -> [(String, a)]
toList = Record (K a) r -> [(String, a)]
forall k (r :: Row k) a.
KnownFields r =>
Record (K a) r -> [(String, a)]
A.toList

-- | Analogue of 'Prelude.sequenceA'
sequenceA :: Applicative m => Record (m :.: f) r -> m (Record f r)
sequenceA :: Record (m :.: f) r -> m (Record f r)
sequenceA = Record (m :.: f) r -> m (Record f r)
forall k (m :: * -> *) (f :: k -> *) (r :: Row k).
Applicative m =>
Record (m :.: f) r -> m (Record f r)
A.sequenceA

-- | Simplified form of 'sequenceA'
sequenceA' :: Applicative m => Record m r -> m (Record I r)
sequenceA' :: Record m r -> m (Record I r)
sequenceA' = Record m r -> m (Record I r)
forall (m :: * -> *) (r :: Row *).
Applicative m =>
Record m r -> m (Record I r)
A.sequenceA'

-- | Analogue of 'Prelude.zip'
zip :: Record f r -> Record g r -> Record (Product f g) r
zip :: Record f r -> Record g r -> Record (Product f g) r
zip = Record f r -> Record g r -> Record (Product f g) r
forall k (f :: k -> *) (r :: Row k) (g :: k -> *).
Record f r -> Record g r -> Record (Product f g) r
A.zip

-- | Analogue of 'Prelude.zipWith'
zipWith ::
     (forall x. f x -> g x -> h x)
  -> Record f r -> Record g r -> Record h r
zipWith :: (forall (x :: k). f x -> g x -> h x)
-> Record f r -> Record g r -> Record h r
zipWith forall (x :: k). f x -> g x -> h x
f = (forall (x :: k). f x -> g x -> h x)
-> Record f r -> Record g r -> Record h r
forall k (f :: k -> *) (g :: k -> *) (h :: k -> *) (r :: Row k).
(forall (x :: k). f x -> g x -> h x)
-> Record f r -> Record g r -> Record h r
A.zipWith forall (x :: k). f x -> g x -> h x
f

-- | Analogue of 'Control.Monad.zipWithM'
zipWithM ::
     Applicative m
  => (forall x. f x -> g x -> m (h x))
  -> Record f r -> Record g r -> m (Record h r)
zipWithM :: (forall (x :: k). f x -> g x -> m (h x))
-> Record f r -> Record g r -> m (Record h r)
zipWithM forall (x :: k). f x -> g x -> m (h x)
f = (forall (x :: k). f x -> g x -> m (h x))
-> Record f r -> Record g r -> m (Record h r)
forall k (m :: * -> *) (f :: k -> *) (g :: k -> *) (h :: k -> *)
       (r :: Row k).
Applicative m =>
(forall (x :: k). f x -> g x -> m (h x))
-> Record f r -> Record g r -> m (Record h r)
A.zipWithM forall (x :: k). f x -> g x -> m (h x)
f

-- | 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
czipWith :: Proxy c
-> (forall (x :: k). c x => f x -> g x -> h x)
-> Record f r
-> Record g r
-> Record h r
czipWith Proxy c
p forall (x :: k). c x => f x -> g x -> h x
f = Proxy c
-> (forall (x :: k). c x => f x -> g x -> h x)
-> Record f r
-> Record g r
-> Record h r
forall k (r :: Row k) (c :: k -> Constraint) (f :: k -> *)
       (g :: k -> *) (h :: k -> *).
AllFields r c =>
Proxy c
-> (forall (x :: k). c x => f x -> g x -> h x)
-> Record f r
-> Record g r
-> Record h r
A.czipWith Proxy c
p forall (x :: k). c x => f x -> g x -> h x
f

-- | 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)
czipWithM :: Proxy c
-> (forall (x :: k). c x => f x -> g x -> m (h x))
-> Record f r
-> Record g r
-> m (Record h r)
czipWithM Proxy c
p forall (x :: k). c x => f x -> g x -> m (h x)
f = Proxy c
-> (forall (x :: k). c x => f x -> g x -> m (h x))
-> Record f r
-> Record g r
-> m (Record h r)
forall k (m :: * -> *) (r :: Row k) (c :: k -> Constraint)
       (f :: k -> *) (g :: k -> *) (h :: k -> *).
(Applicative m, AllFields r c) =>
Proxy c
-> (forall (x :: k). c x => f x -> g x -> m (h x))
-> Record f r
-> Record g r
-> m (Record h r)
A.czipWithM Proxy c
p forall (x :: k). c x => f x -> g x -> m (h x)
f

{-------------------------------------------------------------------------------
  Constraint reification and reflection
-------------------------------------------------------------------------------}

-- | Record of dictionaries
--
-- This reifies an 'AllFields' constraint as a record.
--
-- Inverse to 'reflectKnownFields'.
reifyAllFields :: AllFields r c => proxy c -> Record (Dict c) r
reifyAllFields :: proxy c -> Record (Dict c) r
reifyAllFields = proxy c -> Record (Dict c) r
forall k (r :: Row k) (c :: k -> Constraint)
       (proxy :: (k -> Constraint) -> *).
AllFields r c =>
proxy c -> Record (Dict c) r
A.reifyAllFields

-- | Establish 'AllFields' from a record of dictionaries
--
-- Inverse to 'reifyKnownFields'.
reflectAllFields :: Record (Dict c) r -> Reflected (AllFields r c)
reflectAllFields :: Record (Dict c) r -> Reflected (AllFields r c)
reflectAllFields = Record (Dict c) r -> Reflected (AllFields r c)
forall k (c :: k -> Constraint) (r :: Row k).
Record (Dict c) r -> Reflected (AllFields r c)
A.reflectAllFields

-- | Record of field names
--
-- This reifies a 'KnownFields' constraint as a record.
--
-- Inverse to 'reflectAllFields'.
reifyKnownFields :: KnownFields r => proxy r -> Record (K String) r
reifyKnownFields :: proxy r -> Record (K String) r
reifyKnownFields = proxy r -> Record (K String) r
forall k (r :: Row k) (proxy :: Row k -> *).
KnownFields r =>
proxy r -> Record (K String) r
A.reifyKnownFields

-- | Establish 'KnownFields' from a record of field names
--
-- Inverse to 'reifyAllFields'.
reflectKnownFields :: Record (K String) r -> Reflected (KnownFields r)
reflectKnownFields :: Record (K String) r -> Reflected (KnownFields r)
reflectKnownFields = Record (K String) r -> Reflected (KnownFields r)
forall k (r :: Row k).
Record (K String) r -> Reflected (KnownFields r)
A.reflectKnownFields

-- | 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 (A.InRow r) r'
reifySubRow :: Record (InRow r) r'
reifySubRow = Record (InRow r) r'
forall k (r :: Row k) (r' :: Row k).
(SubRow r r', KnownFields r') =>
Record (InRow r) r'
A.reifySubRow

-- | Establish 'SubRow' from a record of evidence.
--
-- Inverse to 'reifySubRow'.
reflectSubRow :: Record (A.InRow r) r' -> Reflected (SubRow r r')
reflectSubRow :: Record (InRow r) r' -> Reflected (SubRow r r')
reflectSubRow = Record (InRow r) r' -> Reflected (SubRow r r')
forall k (r :: Row k) (r' :: Row k).
Record (InRow r) r' -> Reflected (SubRow r r')
A.reflectSubRow

{-------------------------------------------------------------------------------
  Existential records
-------------------------------------------------------------------------------}

-- | 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
-- 'Data.Typeable.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)] -> A.SomeRecord f
someRecord :: [(String, Some f)] -> SomeRecord f
someRecord = [(String, Some f)] -> SomeRecord f
forall k (f :: k -> *). [(String, Some f)] -> SomeRecord f
A.someRecord

{-------------------------------------------------------------------------------
  Experimental integration with @typelet@
-------------------------------------------------------------------------------}

-- | 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
letRecordT :: (forall (r' :: Row k). Let r' r => Proxy r' -> Record f r)
-> Record f r
letRecordT forall (r' :: Row k). Let r' r => Proxy r' -> Record f r
f = (forall (r' :: Row k). Let r' r => Proxy r' -> Record f r)
-> Record f r
forall k (r :: Row k) (f :: k -> *).
(forall (r' :: Row k). Let r' r => Proxy r' -> Record f r)
-> Record f r
A.letRecordT forall (r' :: Row k). Let r' r => Proxy r' -> Record f r
f

-- | Insert field into a record and introduce type variable for the result
letInsertAs :: forall r r' f n a.
     Proxy r       -- ^ Type of the record we are constructing
  -> Field n       -- ^ New field to be inserted
  -> f a           -- ^ Value of the new field
  -> Record f r'   -- ^ Record constructed so far
  -> (forall r''. Let r'' (n := a : r') => Record f r'' -> Record f r)
                   -- ^ Assign type variable to new partial record, and continue
  -> Record f r
letInsertAs :: Proxy r
-> Field n
-> f a
-> Record f r'
-> (forall (r'' :: Row k).
    Let r'' ((n ':= a) : r') =>
    Record f r'' -> Record f r)
-> Record f r
letInsertAs Proxy r
p Field n
n f a
x Record f r'
r forall (r'' :: Row k).
Let r'' ((n ':= a) : r') =>
Record f r'' -> Record f r
f = Proxy r
-> Field n
-> f a
-> Record f r'
-> (forall (r'' :: Row k).
    Let r'' ((n ':= a) : r') =>
    Record f r'' -> Record f r)
-> Record f r
forall k (r :: Row k) (r' :: Row k) (f :: k -> *) (n :: Symbol)
       (a :: k).
Proxy r
-> Field n
-> f a
-> Record f r'
-> (forall (r'' :: Row k).
    Let r'' ((n ':= a) : r') =>
    Record f r'' -> Record f r)
-> Record f r
A.letInsertAs Proxy r
p Field n
n f a
x Record f r'
r forall (r'' :: Row k).
Let r'' ((n ':= a) : r') =>
Record f r'' -> Record f r
f