pure-borrow
Safe HaskellNone
LanguageGHC2021

Data.Record.Linear.Borrow.Experimental.PatternMatch

Description

An experimental module for splitting a borrow of a record by pattern matching on it. If you want to split out a field gradually and partially, see also Data.Record.Linear.Borrow.Experimental.Split.

The API is subject to future change.

Synopsis

Label Type

type RecordLabel a (f :: Symbol) v = RecordLabel' a '(f, v) Source #

RecordLabel r f a witnesses that the record type r has a field named f of type a. Intended to be constructed with OverloadedLabels extension, so that you can construct it by #f syntax when the field f of a is imported in the current scope.

You can also expose RecordLabel only, so that you can allow users to access such fields while internal implementation unexposed.

Single Field Accessor

(.#) :: forall (bk :: BorrowKind) (α :: Lifetime) a (field :: Symbol) val. Borrow bk α a %1 -> RecordLabel a field val %1 -> Borrow bk α val Source #

recBor .# #f divides a record borrow recBor into a borrow of the field f.

This is (.@) specialised to RecordLabel for better type inference. To access multiple fields, you can use (.@) with a tuple of RecordLabels or RecordLabels. See Splitting a record borrow into pieces for more details.

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 (.@) operator for splitting a borrow of a record into FieldBorrows of its fields. Consider the following:

>>> import Data.Ref.Linear (Ref)
>>> import Data.Vector.Mutable.Linear.Borrow (Vector)
>>> import Control.Monad.Borrow.Pure.BO
>>> data MyRecord = MyRecord { int :: Ref Int, strs :: Vector String, bool :: Ref Bool }

Suppose we have a mutable borrow of some MyRecord:

>>> :{
mutRec :: Mut α (MyRecord)
mutRec = undefined
:}

So, let's divide the mutable borrow into several pieces with (.@). First, we need to enable OverloadedLabels extension to construct RecordLabels:

>>> :set -XOverloadedLabels

First, we just want to divide into all the fields, in arbitrary order:

>>> (mutStrs, mutBool, mutInt) = mutRec .@ (#strs, #bool, #int)
>>> :t mutStrs
mutStrs :: Borrow 'Mut α (Vector String)
>>> :t mutBool
mutBool :: Borrow 'Mut α (Ref Bool)
>>> :t mutInt
mutInt :: Borrow 'Mut α (Ref Int)

Or, we can just divide into some of the fields (say, bool and strs):

>>> (mutStrs, mutBool) = mutRec .@ (#strs, #bool)
>>> :t mutStrs
mutStrs :: Borrow 'Mut α (Vector String)
>>> :t mutBool
mutBool :: Borrow 'Mut α (Ref Bool)

Specifying the same field more than once results in a type error:

mutRec .@ (#strs, #bool, #strs)
-- error: Split record fields must be distinct, but got duplicate field: "strs"

In genral, (.@) accepts any eliminator of a record borrow, which is typically one of the following:

  1. A tuple of RecordLabels without duplcations (currently 2 to 5 components), or
  2. A heterogeneous list RecordLabels of RecordLabels, constructed with (:#-) and RNil, without duplcations on fields.

And fields not listed within the eliminator are not accessible after the split. The examples so far uses tuples as eliminators, but you can also use RecordLabels as follows:

>>> mutStrs :#- mutBool :#- RNil = mutRec .@ #strs :#- #bool :#- RNil

RecordLabels will be mapped to FieldBorrows after the split, and you can also use (:#-) and RNil for pattern-matching.

Indeed, RecordLabel itself is also a RecordEliminator, but if you are using `#f` syntax for constructing RecordLabel, you cannot use it with .@ operator without type annotation because of the ambiguity. If you just want to access one field, you can use (.#) operator.

APIs

(.@) :: forall elim a (bk :: BorrowKind) (α :: Lifetime). RecordEliminator elim a => Borrow bk α a %1 -> elim %1 -> SplitBorrow elim bk α a infixl 4 Source #

Divides a borrow of a record into multiple FieldBorrows of its fields, according to the given eliminator.

Typically, elim is one of the following:

type RecordLabels a (fs :: [(Symbol, Type)]) = LabelsOrBorrows ('RecordLabelOf a) fs Source #

Heterogeneous record labels. If the record type a is clear from the context, you can construct it with '(:#-)' and RNil with OverloadedLabels extension:

  data MyRecord = MyRecord { foo :: Int, bar :: String, buz :: Bool }
  myLabels :: RecordLabels MyRecord _
  myLabels = #foo :#- #bar :#- #buz :#- RNil

type FieldBorrows (bk :: BorrowKind) (α :: Lifetime) (fs :: [(Symbol, Type)]) = LabelsOrBorrows ('BorrowOf bk α) fs Source #

Heterogeneous FieldBorrows. If the record type a is clear from the context, you can construct it with '(:#-)' and RNil with OverloadedLabels extension:

data MyRecord = MyRecord { foo :: Int, bar :: String, buz :: Bool }

mutRec :: Mut α MyRecord
mutRec = ...

buzMut :#- fooMut :#- RNil = mutRec .@ #buz :#- #foo :#- RNil

data LabelsOrBorrows (h :: Fun) (xs :: [(Symbol, Type)]) where Source #

Constructors

RNil :: forall (h :: Fun). LabelsOrBorrows h ('[] :: [(Symbol, Type)]) 
(:#-) :: forall (h :: Fun) (k :: Symbol) v (xs1 :: [(Symbol, Type)]). Apply h '(k, v) -> LabelsOrBorrows h xs1 -> LabelsOrBorrows h ('(k, v) ': xs1) infixr 5 

Instances

Instances details
Consumable (LabelsOrBorrows h xs) Source # 
Instance details

Defined in Data.Record.Linear.Borrow.Experimental.PatternMatch

Methods

consume :: LabelsOrBorrows h xs %1 -> () #

Affine (LabelsOrBorrows h xs) Source # 
Instance details

Defined in Data.Record.Linear.Borrow.Experimental.PatternMatch

Methods

aff :: LabelsOrBorrows h xs %1 -> Aff (LabelsOrBorrows h xs) Source #

(IsUnique fvs, label ~ 'RecordLabelOf a) => RecordEliminator (LabelsOrBorrows label fvs) a Source # 
Instance details

Defined in Data.Record.Linear.Borrow.Experimental.PatternMatch

Methods

splitRecord :: forall (bk :: BorrowKind) (α :: Lifetime). LabelsOrBorrows label fvs %1 -> Borrow bk α a %1 -> SplitBorrow (LabelsOrBorrows label fvs) bk α a Source #

type SplitBorrow (LabelsOrBorrows label fvs) bk α a Source # 
Instance details

Defined in Data.Record.Linear.Borrow.Experimental.PatternMatch

type SplitBorrow (LabelsOrBorrows label fvs) bk α a

Internal APIs

class RecordEliminator elim a where Source #

A class for *eliminators* of record, which can split a borrow of the whole record into FieldBorrows of its fields. Typically, an eliminator is a tuple of RecordLabels or heterogeneous RecordLabels.

Associated Types

type SplitBorrow elim (bk :: BorrowKind) (α :: Lifetime) a Source #

Methods

splitRecord :: forall (bk :: BorrowKind) (α :: Lifetime). elim %1 -> Borrow bk α a %1 -> SplitBorrow elim bk α a Source #

Instances

Instances details
(IsUnique fvs, label ~ 'RecordLabelOf a) => RecordEliminator (LabelsOrBorrows label fvs) a Source # 
Instance details

Defined in Data.Record.Linear.Borrow.Experimental.PatternMatch

Methods

splitRecord :: forall (bk :: BorrowKind) (α :: Lifetime). LabelsOrBorrows label fvs %1 -> Borrow bk α a %1 -> SplitBorrow (LabelsOrBorrows label fvs) bk α a Source #

(IsRecordLabel' a l f1 v1, IsRecordLabel' a r f2 v2, Distinct f1 f2) => RecordEliminator (l, r) a Source # 
Instance details

Defined in Data.Record.Linear.Borrow.Experimental.PatternMatch

Methods

splitRecord :: forall (bk :: BorrowKind) (α :: Lifetime). (l, r) %1 -> Borrow bk α a %1 -> SplitBorrow (l, r) bk α a Source #

a ~ r => RecordEliminator (RecordLabel' r '(field, val)) a Source # 
Instance details

Defined in Data.Record.Linear.Borrow.Experimental.PatternMatch

Methods

splitRecord :: forall (bk :: BorrowKind) (α :: Lifetime). RecordLabel' r '(field, val) %1 -> Borrow bk α a %1 -> SplitBorrow (RecordLabel' r '(field, val)) bk α a Source #

(IsRecordLabel' a l1 f1 v1, IsRecordLabel' a l2 f2 v2, IsRecordLabel' a l3 f3 v3, Distinct f1 f2, Distinct f1 f3, Distinct f2 f3) => RecordEliminator (l1, l2, l3) a Source # 
Instance details

Defined in Data.Record.Linear.Borrow.Experimental.PatternMatch

Methods

splitRecord :: forall (bk :: BorrowKind) (α :: Lifetime). (l1, l2, l3) %1 -> Borrow bk α a %1 -> SplitBorrow (l1, l2, l3) bk α a Source #

(IsRecordLabel' a l1 f1 v1, IsRecordLabel' a l2 f2 v2, IsRecordLabel' a l3 f3 v3, IsRecordLabel' a l4 f4 v4, Distinct f1 f2, Distinct f1 f3, Distinct f1 f4, Distinct f2 f3, Distinct f2 f4, Distinct f3 f4) => RecordEliminator (l1, l2, l3, l4) a Source # 
Instance details

Defined in Data.Record.Linear.Borrow.Experimental.PatternMatch

Methods

splitRecord :: forall (bk :: BorrowKind) (α :: Lifetime). (l1, l2, l3, l4) %1 -> Borrow bk α a %1 -> SplitBorrow (l1, l2, l3, l4) bk α a Source #

(IsRecordLabel' a l1 f1 v1, IsRecordLabel' a l2 f2 v2, IsRecordLabel' a l3 f3 v3, IsRecordLabel' a l4 f4 v4, IsRecordLabel' a l5 f5 v5, Distinct f1 f2, Distinct f1 f3, Distinct f1 f4, Distinct f1 f5, Distinct f2 f3, Distinct f2 f4, Distinct f2 f5, Distinct f3 f4, Distinct f3 f5, Distinct f4 f5) => RecordEliminator (l1, l2, l3, l4, l5) a Source # 
Instance details

Defined in Data.Record.Linear.Borrow.Experimental.PatternMatch

Methods

splitRecord :: forall (bk :: BorrowKind) (α :: Lifetime). (l1, l2, l3, l4, l5) %1 -> Borrow bk α a %1 -> SplitBorrow (l1, l2, l3, l4, l5) bk α a Source #

data RecordLabel' (r :: TYPE rep) (fldVal :: (Symbol, Type)) where Source #

The actual definition of RecordLabel for type-level hacks.

Constructors

RecLab :: forall (field :: Symbol) r1 a. HasField field r1 a => RecordLabel' r1 '(field, a) 

Instances

Instances details
(HasField field r a, fldVal ~ '(field, a)) => IsLabel field (RecordLabel' r fldVal) Source #

This allows users to use #f for constructing RecordLabel a f v.

Instance details

Defined in Data.Record.Linear.Borrow.Experimental.PatternMatch

Methods

fromLabel :: RecordLabel' r fldVal #

KnownSymbol field => Show (RecordLabel' r '(field, a)) Source # 
Instance details

Defined in Data.Record.Linear.Borrow.Experimental.PatternMatch

Methods

showsPrec :: Int -> RecordLabel' r '(field, a) -> ShowS #

show :: RecordLabel' r '(field, a) -> String #

showList :: [RecordLabel' r '(field, a)] -> ShowS #

a ~ r => RecordEliminator (RecordLabel' r '(field, val)) a Source # 
Instance details

Defined in Data.Record.Linear.Borrow.Experimental.PatternMatch

Methods

splitRecord :: forall (bk :: BorrowKind) (α :: Lifetime). RecordLabel' r '(field, val) %1 -> Borrow bk α a %1 -> SplitBorrow (RecordLabel' r '(field, val)) bk α a Source #

type SplitBorrow (RecordLabel' r '(field, val)) bk α a Source # 
Instance details

Defined in Data.Record.Linear.Borrow.Experimental.PatternMatch

type SplitBorrow (RecordLabel' r '(field, val)) bk α a = Borrow bk α val