## 6.1 Records in General

The module `Record` contains procedures operating on records.

Procedures that iterate over the subtrees of a record operate in ascending order as specified for `Arity`.

`.`

  > `{Value.'.'` `+RC``` `+LI``` `X``}`

  returns the field `X` of `RC` at feature `LI`.

`HasFeature`

  > `{Value.hasFeature` `+RC``` `+LI``` `?B``}`

  tests whether `RC` has feature `LI`.

`CondSelect`

  > `{Value.condSelect` `+RC``` `+LI``` `X``` `Y``}`

  returns the field of `RC` at feature `LI`, if `RC` has feature `LI`. Otherwise, return `X`.

`IsRecord`

  > `{Record.is` `+X``` `?B``}`

  tests whether `X` is a record.

`MakeRecord`

  > `{Record.make` `+L``` `+LIs``` `?R``}`

  returns a new record with label `L`, features `LIs`, and fresh variables at every field. All elements of `LIs` must be pairwise distinct, else an error exception is raised.

  For example, `{MakeRecord L A R}` waits until `L` is bound to a literal, say `b`, and `A` is bound to a list of literals and integers, say `[c d 1]`, and then binds `R` to `b(_ c: _ d: _)`.

`clone`

  > `{Record.clone` `+R1``` `?R2``}`

  returns a record `R2` with the same label and features as `R1` and fresh variables at every field.

`Label`

  > `{Record.label` `+R``` `?L``}`

  returns the label of `R` in `L`.

`Width`

  > `{Record.width` `+R``` `?I``}`

  returns the width of `R` in `I`.

`Arity`

  > `{Record.arity` `+R``` `?LIs``}`

  returns the arity `LIs` of `R`. The arity of `R` is the list of its features, beginning with all integer features in ascending order, followed by the literal features. The atomic literals occur in ascending order interspersed with names.

  For example, `{Arity a(nil 7 c: 1 b: c)}` yields `[1 2 b c]` as output.

`Adjoin`

  > `{Record.adjoin` `+R1``` `+R2``` `?R3``}`

  returns the result of adjoining `R2` to `R1`. Note that features and label in R2 take precedence over R1.

  For example,

  > `{Adjoin a(a b c: 1) b(4 b: 3 c: 2)}`

  yields the record `b(4 b b: 3 c: 2)` as output.

`AdjoinAt`

  > `{Record.adjoinAt` `+R1``` `+LI``` `X``` `?R2``}`

  binds `R2` to the result of adjoining the field `X` to `R1` at feature `LI`.

  For example,

  > `{AdjoinAt a(a c: 1) 2 b}`

  yields `a(a b c: 1)` as output, whereas

  > `{AdjoinAt a(a c: 1) c b}`

  yields `a(a c: b)` as output.

`AdjoinList`

  > `{Record.adjoinList` `+R1``` `+Ts``` `?R2``}`

  binds `R2` to the result of adjoining to `R1` all entries of `Ts`, a finite list of pairs whose first components are literals or integers, representing features. Features further to the right overwrite features further to the left.

  For example,

  > `{AdjoinList a(b:1 c:2) [d#3 c#4 d#5]}`

  yields `a(b: 1 c: 4 d: 5)` as output.

`subtract`

  > `{Record.subtract` `+R1``` `+LI``` `?R2``}`

  If `R1` has feature `LI`, returns record `R1` with feature `LI` removed. Otherwise, returns `R1`.

`subtractList`

  > `{Record.subtractList` `+R1``` `+LIs``` `?R2``}`

  Returns record `R1` with all features in `LIs` removed.

  For example,

  > `{Record.subtractList f(jim: 1 jack: 2 jesse: 4) [jesse jim]}`

  returns the record `f(jack: 2)`.

`zip`

  > `{Record.zip` `+R1``` `+R2``` `+P``` `?R3``}`

  Given two records `R1` and `R2` and a ternary procedure `P`, `R3` is bound to a record with the same label as `R1` and those features which are common to `R1` and `R2`. Features appearing only in one of the records are silently dropped. Each fields `X` of `R3` is computed by applying `{``P``` `R1``.``X``` `R2``.``X``` `R3``.``X``}`.

  For example,

  > `{Record.zip
  > f(jim: 1 jack: 2 jesse: 4)
  > g(jim: a jack: b joe: c)
  > fun {$ X Y} X#Y end}`

  yields as output the record `f(jim: 1#a jack: 2#b)`.

`toList`

  > `{Record.toList` `+R``` `?Xs``}`

  binds `Xs` to list of all fields of `R` in the order as given by `Arity` (which see).

  For example,

  > `{Record.toList f(a a: 2 b: 3)}`

  yields `[a 2 3]` as output.

`toListInd`

  > `{Record.toListInd` `+R``` `?Ts``}`

  binds `Ts` to the property list that contains the feature-field pairs of `R` in the order as given by `Arity` (which see).

  For example,

  > `{Record.toListInd f(a a: 2 b: 3)}`

  yields `[1#a a#2 b#3]` as output.

`toDictionary`

  > `{Record.toDictionary` `+R``` `?Dictionary``}`

  returns a dictionary `Dictionary` whose keys and their entries correspond to the features and their fields of `R`.

All of the following procedures are provided in two versions. The so-called index version passes to the procedures an additional index as first actual argument. The index is an integer or a literal giving the feature of the field currently processed.

`map`

  > `{Record.map` `+R1``` `+P``` `?R2``}`

  returns a record with same label and arity as `R1`, whose fields are computed by applying the binary procedure `P` to all fields of `R1`.

  For example,

  > `{Record.map a(12 b: 13 c: 1) IntToFloat}`

  yields the record `a(12.0 b: 13.0 c: 1.0)` as output.

`mapInd`

  > `{Record.mapInd` `+R1``` `+P``` `?R2``}`

  is similar to `Record.map`, but the ternary procedure `P` is applied with the index as first actual argument.

  For example,

  > `{Record.mapInd a(1: d 3: a f: e) fun {$ I A} A(I) end}`

  yields the record `a(1: d(1) 3: a(3) f: e(f))` as output.

`foldL`

  > `{Record.foldL` `+R``` `+P``` `X``` `?Y``}`

`foldR`

  > `{Record.foldR` `+R``` `+P``` `X``` `?Y``}`

  Used for folding the fields of `R` by applying the ternary procedure `P`.

  Suppose that `R` has the arity `[``F1``` ...`` `Fn``]`. Applying the left folding procedure `{Record.foldL` `R``` `P``` `Z``` `Out``}` reduces to

  > `{``P``` ...`{``P``{``P``` `Z``` `R``.``F1``}` `R``.``F2``` ...`` `R``.``Fn``` `Out``}`

  The first actual argument of `P` is the accumulator in which the result of the previous application or the start value `Z` is passed. The second actual argument is a field of `R`.

  Besides the left folding procedure there exists a right folding variant. The application `{Record.foldR` `R``` `P``` `Z``` `Out``}` reduces to

  > `{``P``` `R``.``F1``{``P``` `R``.``F2``` ...`{``P``` `R``.``Fn``` `Z``}` ...`` `Out``}`

  The first actual argument of `P` is a field of `R`; the second actual argument is the accumulator in which the result of the previous application or the start value `Z` is passed.

  For example,

  > `{Record.foldL a(3 a: 7 b: 4) fun {$ Xr X} X|Xr end nil}`

  yields the output `[4 7 3]`, whereas

  > `{Record.foldR a(3 a: 7 b: 4) fun {$ X Xr} X|Xr end nil}`

  yields the output `[3 7 4]`.

`foldLInd`

  > `{Record.foldLInd` `+R``` `+P``` `X``` `?Y``}`

`foldRInd`

  > `{Record.foldRInd` `+R``` `+P``` `X``` `?Y``}`

  are similar to `Record.foldL` and `Record.foldR`, but the 4-ary procedure `P` is applied with the current index as first actual argument.

`forAll`

  > `{Record.forAll` `+R``` `+PO``}`

  applies the unary procedure or object `PO` to each field of `R`.

  Suppose that the arity of `R` is `[``F1``` ...`` `Fn``]`. The application `{Record.forAll` `R``` `P``}` reduces to the sequence of statements

  > `{``P``` `R``.``F1``}` ...`{``P``` `R``.``Fn``}`

  For example,

  > `{Record.forAll O1#O2#O3 proc {$ O} {O do()} end}`

  sends the message `do()` to the objects `O1`, `O2`, and `O3`.

`forAllInd`

  > `{Record.forAllInd` `+R``` `+P``}`

  is similar to `Record.forAll`, but the binary procedure `P` is applied with the current index as first actual argument.

  For example, assuming `O1`, `O2`, and `O3` are objects,

  > `{Record.forAllInd a(do: O1 stop: O2 run: O3)
  > proc {$ M O} {O M} end}`

  sends the message `do` to the object `O1`, the message `stop` to `O2`, and the message `run` to `O3`.

`all`

  > `{Record.all` `+R``` `+P``` `?B``}`

`some`

  > `{Record.some` `+R``` `+P``` `?B``}`

  tests whether the unary boolean function `P` yields `true` when applied to all fields resp. some field of `R`. Stops at the first field for which `P` yields `false` resp. `true`. The fields are tested in the order given by `Arity` (which see).

`allInd`

  > `{Record.allInd` `+R``` `+P``` `?B``}`

`someInd`

  > `{Record.someInd` `+R``` `+P``` `?B``}`

  is similar to `Record.all` resp. `Record.some`, but the binary boolean function `P` is applied with the current index as first actual argument.

`filter`

  > `{Record.filter` `+R1``` `+P``` `?R2``}`

`partition`

  > `{Record.partition` `+R1``` `+P``` `?R2``` `?R3``}`

  `Record.filter` computes a record `R2` which contains all the features and fields of the record `R1` for which the unary boolean procedure `P` applied to the field yields `true`. `Record.partition` works similarly, but returns in `R3` a record with all remaining fields of `R1`.

  For example, the application

  > `{Record.partition a(1 4 7 a: 3 b: 6 c: 5) IsOdd ?R2 ?R3}`

  returns `a(1: 1 3: 7 a: 3 c: 5)` in `R2` and `a(2: 4 b: 6)` in `R3`.

`filterInd`

  > `{Record.filterInd` `+R1``` `+P``` `?R2``}`

`partitionInd`

  > `{Record.partitionInd` `+R1``` `+P``` `?R2``` `?R3``}`

  are similar to `Record.filter` and `Record.partition`, but the binary boolean function `P` is applied with the current index as first actual argument.

`takeWhile`

  > `{Record.takeWhile` `+R1``` `+P``` `?R2``}`

`dropWhile`

  > `{Record.dropWhile` `+R1``` `+P``` `?R3``}`

`takeDropWhile`

  > `{Record.takeDropWhile` `+R2``` `+P``` `?R2``` `?R3``}`

  While `Record.filter` selects all fields and features of a record which satisfy a certain condition, the procedure `Record.takeWhile` selects only the starting sequence of features and fields which fulfill this condition. The procedure `Record.dropWhile` is dual: It computes a record with the remaining features and fields. `Record.takeWhileDrop` computes both records.

  For example,

  > `{Record.takeWhile a(1 4 7 a: 3 b: 6 c: 5) IsOdd}`

  yields as output `a(1)`, whereas

  > `{Record.dropWhile a(1 4 7 a: 3 b: 6 c: 5) IsOdd}`

  yields `a(2: 4 3: 7 a: 3 b: 6 c: 5)` as output. Both records can be computed simultaneously by

  > `{Record.takeDropWhile a(1 4 7 a: 3 b: 6 c: 5) IsOdd ?R2 ?R3}`

`takeWhileInd`

  > `{Record.takeWhileInd` `+R1``` `+P``` `?R2``}`

`dropWhileInd`

  > `{Record.dropWhileInd` `+R1``` `+P``` `?R3``}`

`takeDropWhileInd`

  > `{Record.takeDropWhileInd` `+R1``` `+P``` `?R2``` `?R3``}`

  are similar to `Record.takeWhile`, `Record.dropWhile` and `Record.takeDropWhile` but the binary boolean function `P` is applied with the current index as first actual argument.

`waitOr`

  > `{Record.waitOr` `+R``` `?LI``}`

  blocks until at least one field of `+R` is determined. Returns the feature `LI` of a determined field. Raises an exception if `R` is not a proper record, that is, if `R` is a literal.

  For example,

  > `{Record.waitOr a(_ b: 1)}`

  returns `b` while

  > `{Record.waitOr a(2 b: _)}`

  returns `1`, and

  > `{Record.waitOr a(_ b: _)}`

  blocks.