| Safe Haskell | None |
|---|---|
| Language | GHC2021 |
Data.Record.Linear.Borrow.Experimental.Split
Description
An experimental module for splitting a borrow of a record gradually and partially. To be used when you need to access more than one fields of a borrowed record, and borrow-out each field as you go. If you can just pattern match on the record borrow once, consider using Data.Record.Linear.Borrow.Experimental.PatternMatch.
The API is subject to future change.
Synopsis
- data RecordLabel (r :: TYPE rep) (field :: Symbol) a
- (.#) :: forall (field :: Symbol) r a (k :: BorrowKind) (α :: Lifetime). Borrow k α r %1 -> RecordLabel r field a -> Borrow k α a
- splitRecord :: forall a (bk :: BorrowKind) (α :: Lifetime) (m :: Multiplicity). SplittableRecord a => Borrow bk α a %m -> SplitRecord a bk α (Fields a)
- data SplitRecord a (bk :: BorrowKind) (α :: Lifetime) (s :: [(Symbol, (Multiplicity, Type))])
- class All (IsFieldOf a :: (Symbol, (Multiplicity, Type)) -> Constraint) (Fields a) => SplittableRecord a
- (-#) :: forall a (field :: Symbol) (fs :: [(Symbol, (Multiplicity, Type))]) x (bk :: BorrowKind) (α :: Lifetime) (m :: Multiplicity). (SplittableRecord a, Lookup field fs ~ 'Just '('One, x)) => SplitRecord a bk α fs %m -> RecordLabel a field x -> (Borrow bk α x, SplitRecord a bk α (Delete field fs))
- (+#) :: forall a (field :: Symbol) (fs :: [(Symbol, (Multiplicity, Type))]) x (bk :: BorrowKind) (α :: Lifetime) (m :: Multiplicity). (SplittableRecord a, Lookup field fs ~ 'Just '('Many, Ur x)) => SplitRecord a bk α fs %m -> RecordLabel a field (Ur x) -> (Ur x, SplitRecord a bk α fs)
- (!#) :: forall a (field :: Symbol) (fs :: [(Symbol, (Multiplicity, Type))]) x (bk :: BorrowKind) (α :: Lifetime) (m :: Multiplicity). (SplittableRecord a, Lookup field fs ~ 'Just '('One, x)) => SplitRecord a bk α fs %m -> RecordLabel a field x -> Borrow bk α x
Label Type
data RecordLabel (r :: TYPE rep) (field :: Symbol) a Source #
witnesses that the record type RecordLabel r field ar has a field named field of type a.
To be used as a label argument for (.#), (-#), (+#), and (!#).
The record label is usually constructed by overloaded labels as `#field` under OverloadedLabels extension.
Instances
| (HasField field r a, field ~ field') => IsLabel field (RecordLabel r field' a) Source # | |
Defined in Data.Record.Linear.Borrow.Experimental.Split Methods fromLabel :: RecordLabel r field' a # | |
Single Field Accessor
(.#) :: forall (field :: Symbol) r a (k :: BorrowKind) (α :: Lifetime). Borrow k α r %1 -> RecordLabel r field a -> Borrow k α a infixl 9 Source #
Borrow-level field accessor.
record returns a borrow of the .# #fieldfield of the record of the same kind.
{-# LANGUAGE OverloadedLabels #-}
data MyRecord = MyRecord {field :: Ref Int, otherField :: Vector String}
recordBor :: Borrow bk α MyRecord
recordBor = ...
fieldOfRecordBor :: Borrow bk α (Ref Int)
fieldOfRecordBor = recordBor .# #field
otherFieldOfRecordBor :: Borrow bk α (Vector String)
otherFieldOfRecordBor = recordBor .# #otherField
In above example, we annotate type of the divided field borows for clarity, but the type can be inferred by the record type and labels.
For more complex, partial splitting of a record, see Splitting a record borrow into pieces for more detail.
Splitting a record borrow into pieces
Overview
(.#) is handy when you need only one field of a borrowed record, but not applicable when you need to access more than one fields.
For that purpose, we provide SplitRecord machinery and associated combinators (-#), (+#), and (!#) for splitting a borrow of a record into borrows of its fields.
In such cases, however, we must ensure that each field of a record borrow is split out at most once.
Here, comes int play: it is representationally same as SplitRecord a bk α fs, but only the fields in Borrow bk α afs remains unsplit.
That is, a field is borrowed by splitting combinator only if it remains in fs type parameter, and the field is removed from fs after splitting.
A record type can be converted into a SplitRecord by splitRecord function, which requires SplittableRecord instance for the record type.
This can be derived generically by deriving Generic and then SplittableRecord for the record type, as follows:
{-# LANGUAGE TemplateHaskell, DataKinds, TypeFamilies, LinearTypes #-}
import Generics.Linear.TH (deriveGeneric)
data MyRecord = MyRecord {field :: Ref Int, otherField :: Vector String}
deriveGeneric ''MyRecord
deriving anyclass instance SplittableRecord MyRecord
Once we have SplittableRecord instance derived, we can now split a record borrow partially, step-by-step using (-#), (+#), and (!#) combinators.
Through out this documentation, suppose we have the following record borrow in scope:
recordBor ::Mutα MyRecord splitRec ::SplitRecordMyRecordMutα '[ '("field", '( 'One, Ref Int)), '("otherField", '( 'One, Vector String))] splitRec = splitRecord recordBor
Borrows-out a linear field
When you want to borrow-out a single linear field from the record, you can use (-#) combinator, as follows:
fieldBor ::Mutα (Ref Int) restBor ::SplitRecordMyRecord Mut α '[ '(otherField, '( 'One, Vector String)))] (fieldBor, restSplit) = splitRec-##field
Here, the borrow to the field of splitRec is borrowed out as fieldBor, and the remaining borrow is represented by restSplit, where only otherField remain unsplit.
We can no longer borrow-out field from restSplit by the type constraints.
Consuming a split record
When you no longer need to borrow any field of a split record, you can just consume a split record, or call (!#) to borrow out a single field from the split record and discard the rest of the record borrow, as follows:
otherFieldBor :: Mut α (Vector String)
otherFieldBor = restSplit !# #otherField
(!#) is analogous to (.#), but it acts on SplitRecord instead of borrow of a record.
APIs
splitRecord :: forall a (bk :: BorrowKind) (α :: Lifetime) (m :: Multiplicity). SplittableRecord a => Borrow bk α a %m -> SplitRecord a bk α (Fields a) Source #
Start subdividing a borrow of a record.
data SplitRecord a (bk :: BorrowKind) (α :: Lifetime) (s :: [(Symbol, (Multiplicity, Type))]) Source #
represents a borrow of a value of type SplitRecord a bk α fsa of borrow kind bk (i.e. Share or Mut) for lifetime α with fs remains unsplit.
That is, if the field f is removed by some combinators like (-#), then the resulting SplitRecord will have f removed from the fs type-level list.
At any time, you can consume SplitRecord when the remaining fields are no longer of interest.
Instances
| Consumable (SplitRecord a bk α fs) Source # | |
Defined in Data.Record.Linear.Borrow.Experimental.Split Methods consume :: SplitRecord a bk α fs %1 -> () # | |
class All (IsFieldOf a :: (Symbol, (Multiplicity, Type)) -> Constraint) (Fields a) => SplittableRecord a Source #
(-#) :: forall a (field :: Symbol) (fs :: [(Symbol, (Multiplicity, Type))]) x (bk :: BorrowKind) (α :: Lifetime) (m :: Multiplicity). (SplittableRecord a, Lookup field fs ~ 'Just '('One, x)) => SplitRecord a bk α fs %m -> RecordLabel a field x -> (Borrow bk α x, SplitRecord a bk α (Delete field fs)) infix 9 Source #
(+#) :: forall a (field :: Symbol) (fs :: [(Symbol, (Multiplicity, Type))]) x (bk :: BorrowKind) (α :: Lifetime) (m :: Multiplicity). (SplittableRecord a, Lookup field fs ~ 'Just '('Many, Ur x)) => SplitRecord a bk α fs %m -> RecordLabel a field (Ur x) -> (Ur x, SplitRecord a bk α fs) infix 9 Source #
(!#) :: forall a (field :: Symbol) (fs :: [(Symbol, (Multiplicity, Type))]) x (bk :: BorrowKind) (α :: Lifetime) (m :: Multiplicity). (SplittableRecord a, Lookup field fs ~ 'Just '('One, x)) => SplitRecord a bk α fs %m -> RecordLabel a field x -> Borrow bk α x infix 9 Source #