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#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.F1R.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.


Denys Duchier, Leif Kornstaedt and Christian Schulte
Version 1.4.0 (20080702)