[m-dev.] for review: record syntax [2]
Simon Taylor
stayl at cs.mu.OZ.AU
Fri Jan 7 14:26:14 AEDT 2000
> > + at node Record syntax
> > + at subsection Record syntax
> > +
> > +Record syntax provides a convenient way to extract or update fields
> > +of data constructors, independent of the definition of the constructor.
>
> I found the division of material between this section and the Field
> access functions section a bit confusing. From the names, I'd expect
> this section to just cover adding labels to type declarations, and the
> fact that doing so generates a couple of functions for you, and the
> other section to cover use of those functions.
What name would you suggest for the "Record syntax" section?
> Much of what is said below is said better in the "Field access
> functions" section. You may be able to remove much of the following in
> this section and yield a clearer document. But I'll comment on this
> stuff anyway, in case you want to keep it or move it to that section.
The "Record syntax" section only describes the transformation of the
syntactic sugar into function calls -- I don't see what could be moved out.
> > +A field within a term is specified by a list of
> > +(possibly module-qualified) field names separated by the operator `^'.
> > +For example @samp{field1}, @samp{module__field1} and
> > + at samp{field1 ^ field2} are all valid field specifiers.
>
> I think it's easier to understand this if you just say that
>
> @meta{expression} @samp{^} @meta{field}
>
> is an expression specifying the @meta{field} field of the term
> specified by @meta{expression}, and that naturally, you can chain
> these.
OK.
> In the discussion below, I think field names should be lower case, and
> in the @meta{} face, since they're meta variables standing for
> function names, unless this contradicts existing practise in the
> manual.
Done.
> > + at var{Field1} @dots{} @var{FieldN} must be valid field names.
>
> As I understand it, this isn't quite true. Each FieldN may also be a
> function. It may be clearer if you just come out and say that
> @samp{^} is just an alternative syntax for function application, and
> that specifying a field name in a type declaration just defines a
> unary accessor function. This would be a good clarifying explanation
> after introducing this as above.
Done.
> One detail could use clarification: Can you write
>
> Foo ^ bar(3)
>
> and have that turn into
>
> bar(3, Foo)?
> Also, how about
>
> Accessor = fieldname,
> Variable = Foo ^ Accessor?
Allowing this would make it difficult to generate field selectors inline.
The documentation now makes it clear that the field specifiers
must be function names.
> Before seeing this general, hairy example, I think it would be gentler
> to give a simple
>
> Rec1 = Rec0^salary := Newsalary
>
> sort of example.
Done.
> I think it would help to insert the line
>
> OldField_N_Minus_1 = OldField_N_Minus_2 ^ Field_N_Minus_2,
Done.
> > +The arguments of constructor definitions may be labelled.
> > +These labels can be used to conveniently extract and update fields
> > +of a constructor in a manner independent of the definition of the
> > +constructor (@pxref{Field access functions}). A labelled argument
> > +is of the form `@code{@var{FieldName} :: @var{Type}}'.
>
> I think you should mention that for each label @meta{label}, a
> function @meta{label}/1 and a function @meta{label}@code{:=}/2 are
> generated.
The paragraph you quoted is really just a pointer to the
"Field access functions" section, which goes into that
in detail.
> I assume that if this type declaration appears in an
> interface section, then these functions are exported, too? This
> should be mentioned here.
Done.
> Also, how about this:
>
> :- type employee --->
> indian(name::string, salary::float)
> ; chief(name::string, salary::float,
> manages::list(employee))
>
> Probably a bad example, but I hope you see what I'm doing. This seems
> clear enough and quite useful. In this case, name/1 and salary/1
> should be det, but manages/1 would be semidet. Again, this should be
> discussed.
I've added a sentence to make it clear that it is an error for two fields
in the same module to have the same name.
> > + at node Field access functions
> > + at section Field access functions
> > +
> > +Fields of constructors of discriminated union types may be
> > +labelled.
>
> Cross reference to record declaration section.
Done.
> Also, I think you should mention in this section that ':=' is just
> syntactic sugar, and that the expression on the left of the := must be
> a function application (usually written using ^ notation), and that
> the function name must be visible in the source file (known at compile
> time).
The description of ':=' is in the "Record syntax" section (there's a pointer
to that at the top of the "Field access functions" section.
Also, the list of field names on the left of `:=' is not a function
application, so it would be pretty confusing to describe it that way.
> > These labels can be used to extract and update individual
> > +fields of a constructor a manner independent of the definition of
>
> s/constructor a/term in a/
>
> > + at example
> > +:- func 'field1:='(type1, int) = type1.
> > +
> > +'field1:='(Term, Field1) = 'builtin field1:='(Term, Field1) :-
> > + ( Field1 < 0 ->
> > + error("'field1:=': negative value for field1")
> > + ;
> > + true
> > + ).
> > + at end example
>
> I don't really see the value in this 'builtin ...' mechanism.
> Wouldn't it be just as simple for the user to give the field a
> different name and define the functions using that name? That would
> avoid having to explain all this (and the confusion of your earlier
> example showing field1/1, field2/1, 'field1:='/1, and 'field2:='/1
> functions being generated, but no 'builtin ...' versions of these,
> which I would have expected).
You can think of the 'builtin ...' mechanism as just enforcing a convention
on the name of the renamed field, rather than making the user come up
with another name.
There's a relative diff below.
Thanks,
Simon.
--- reference_manual.texi 2000/01/05 23:41:32 1.5
+++ reference_manual.texi 2000/01/07 03:08:14
@@ -723,29 +723,33 @@
transform(V_in, V_out, :=(Term)) = (V_out = Term)
@end example
- at item @var{Term} := ^ @var{Field1} ^ ... ^ @var{FieldN}
-Unifies @var{Term} with the field of the implicit DCG argument
-labelled by @var{Field}.
+ at item @var{Term} := ^ @var{field1} ^ ... ^ @var{fieldN}
+A DCG field selection.
+Unifies @var{Term} with the result of applying the functions
+ at var{field1} @dots{} @var{fieldN} to the implicit DCG argument.
@var{Term} must be a valid data-term.
- at var{Field1} @dots{} @var{FieldN} must be valid field names.
+For each @var{field} in @w{@var{field1} @dots{} @var{fieldN}} there must be
+a visible function named @samp{@var{field}/1}.
@xref{Record syntax}.
Semantics:
@example
-transform(V_in, V_out, Term := ^ Field1 ^ @dots{} ^ FieldN ) =
- (Term = V_in ^ Field1 ^ @dots{} ^ FieldN, V_out = V_in)
+transform(V_in, V_out, Term := ^ field1 ^ @dots{} ^ fieldN) =
+ (Term = V_in ^ field1 ^ @dots{} ^ fieldN, V_out = V_in)
@end example
- at item ^ @var{Field} := @var{Term}
+ at item ^ @var{field} := @var{Term}
+A DCG field update.
Replaces a field in the implicit DCG argument.
@var{Term} must be a valid data-term.
- at var{Field1} @dots{} @var{FieldN} must be valid field names.
+For each @var{field} in @w{@var{field1} @dots{} @var{fieldN}} there must be
+visible functions named @samp{@var{field}/1} and @samp{'@var{field}:='/2}.
@xref{Record syntax}.
Semantics:
@example
-transform(V_in, V_out, ^ Field1 ^ @dots{} ^ FieldN := Term) =
- (V_out = V_in ^ Field1 ^ @dots{} ^ FieldN := Term)
+transform(V_in, V_out, ^ field1 ^ @dots{} ^ fieldN := Term) =
+ (V_out = V_in ^ field1 ^ @dots{} ^ fieldN := Term)
@end example
@item @var{DCG-call}
@@ -801,44 +805,48 @@
@node Record syntax
@subsection Record syntax
-Record syntax provides a convenient way to extract or update fields
+Record syntax provides a convenient way to select or update fields
of data constructors, independent of the definition of the constructor.
-A field within a term is specified by a list of
-(possibly module-qualified) field names separated by the operator `^'.
-For example @samp{field1}, @samp{module__field1} and
- at samp{field1 ^ field2} are all valid field specifiers.
-
Record syntax expressions are transformed into sequences of calls
-to field extraction or update functions (@pxref{Field access functions}).
+to field selection or update functions (@pxref{Field access functions}).
@table @code
- at item @var{Term} ^ @var{Field1} ^ @dots{} ^ @var{FieldN}
+ at item @var{Term} ^ @var{field}
+
+A field selection, equivalent to @code{@var{field}(@var{Term})}.
-A field extraction.
@var{Term} must be a valid data-term.
- at var{Field1} @dots{} @var{FieldN} must be valid field names.
+ at var{field} must be the name of a visible unary function, possibly a
+function generated for a labelled field of a data constructor.
-This is equivalent to a sequence of function calls:
- at example
- at var{FieldN}(@dots{} @var{Field1}(@var{Term}) @dots{}).
- at end example
+Field selections may be chained, as in @code{Term ^ field1 ^ field2},
+which is equivalent to @code{field2(field1(Term))}.
- at item @var{Term} ^ @var{Field1} ^ @dots{} ^ @var{FieldN} := @var{FieldValue}
+ at item @var{Term} ^ @var{field1} ^ @dots{} ^ @var{fieldN} := @var{FieldValue}
A field update.
+
@var{Term} must be a valid data-term.
- at var{Field1} @dots{} @var{FieldN} must be valid field names.
+For each @var{field} in @w{@var{field1} @dots{} @var{fieldN}} there must be
+visible functions named @samp{@var{field}/1} and @samp{'@var{field}:='/2}.
+Typically, these functions will be automatically generated by the compiler
+for a labelled field of a data constructor, although they may be supplied
+by the user.
+
+The term @code{Term ^ field := FieldValue} is equivalent
+to @code{'field:='(Term, FieldValue)}.
-This is equivalent to the code:
+The general case above is equivalent to the code:
@example
-OldField1 = Term ^ Field1,
-OldField2 = OldField1 ^ OldField2,
+OldField1 = @var{field1}(Term),
+OldField2 = @var{field2}(OldField1),
@dots{}
-NewField_N_Minus_1 = 'FieldN:='(OldField_N_Minus_1, FieldValue),
+OldField_N_Minus_1 = @var{field_N_Minus_2}(OldField_N_Minus_2),
+NewField_N_Minus_1 = '@var{fieldN}:='(OldField_N_Minus_1, FieldValue),
@dots{}
-NewField1 = 'Field2:='(OldField1, NewField2),
-Result = 'Field1:='(Term, NewField1)
+NewField1 = '@var{field2}:='(OldField1, NewField2),
+Result = '@var{field1}:='(Term, NewField1)
@end example
@end table
@@ -1077,10 +1085,12 @@
transparent.
The arguments of constructor definitions may be labelled.
-These labels can be used to conveniently extract and update fields
-of a constructor in a manner independent of the definition of the
-constructor (@pxref{Field access functions}). A labelled argument
-is of the form `@code{@var{FieldName} :: @var{Type}}'.
+These labels cause the compiler to generate functions which can
+be used to conveniently select and update fields of a term
+in a manner independent of the definition of the type
+(@pxref{Field access functions}). A labelled argument is of the
+form @w{@code{@var{fieldname} :: @var{Type}}}. It is an error for
+two fields in the same module to have the same label.
Here are some examples of discriminated union definitions:
@@ -1198,8 +1208,8 @@
Abstract types may be defined as either discriminated union types
or as equivalence types.
- at node Predicate and function types
- at section Predicate and function types
+ at node Predicate and function types
+ at section Predicate and function types
The argument types of each predicate
must be explicitly declared with a @samp{:- pred} declaration.
@@ -1298,58 +1308,64 @@
@section Field access functions
Fields of constructors of discriminated union types may be
-labelled. These labels can be used to extract and update individual
-fields of a constructor a manner independent of the definition of
-the constructor.
+labelled (@pxref{Discriminated unions}). These labels cause the
+compiler to generate functions which can be used to select and update
+fields of a term in a manner independent of the definition of the type.
The Mercury language includes syntactic sugar to make it more convenient
-to extract and update fields inside nested terms (@pxref{Record syntax})
-and to extract and update fields of the DCG arguments of a
+to select and update fields inside nested terms (@pxref{Record syntax})
+and to select and update fields of the DCG arguments of a
clause (@pxref{DCG-goals}).
@menu
-* Field extraction::
+* Field selection::
* Field update::
* Overriding field access functions::
* Field access examples::
@end menu
- at node Field extraction
- at subsection Field extraction
+ at node Field selection
+ at subsection Field selection
@example
- at var{Field}(@var{Term})
+ at var{field}(@var{Term})
@end example
-Each field label @samp{@var{Field}} in a constructor causes generation
-of a field extraction function @samp{@var{Field}/1}, which takes a data-term
+Each field label @samp{@var{field}} in a constructor causes generation
+of a field selection function @samp{@var{field}/1}, which takes a data-term
of the same type as the constructor and returns the value of the
labelled field, failing if the top-level constructor of the argument
is not the constructor containing the field.
-By default, this function has no modes --- the modes are inferred at
+If the declaration of the field is in the interface section of the module,
+the corresponding field selection function is also exported from the module.
+
+By default, this function has no declared modes --- the modes are inferred at
each call to the function.
An explicit lambda expression must be used to create a higher-order term
-from a field extraction function, unless a mode declaration is supplied.
+from a field selection function, unless a mode declaration is supplied.
@node Field update
@subsection Field update
@example
-'@var{Field}:='(@var{Term}, @var{ValueTerm})
+'@var{field}:='(@var{Term}, @var{ValueTerm})
@end example
-Each field label @samp{@var{Field}} in a constructor causes generation
-of a field update function @samp{'@var{Field}:='/2}.
+Each field label @samp{@var{field}} in a constructor causes generation
+of a field update function @samp{'@var{field}:='/2}.
The first argument of this function is a data-term of the same type as the
constructor. The second argument is a data-term of the same type as the
labelled field. The return value is a copy of the first argument with
value of the labelled field replaced by the second argument.
- at samp{'@var{Field}:='/2} fails if the top-level constructor of the
+ at samp{'@var{field}:='/2} fails if the top-level constructor of the
first argument is not the constructor containing the labelled field.
-By default, this function has no modes --- the modes
+If the declaration of the field is in the interface section of the module,
+the corresponding field update function is also exported from the module.
+
+By default, this function has no declared modes --- the modes
are inferred at each call to the function.
Some fields cannot be updated using field update functions.
@@ -1373,13 +1389,13 @@
@subsection Overriding field access functions
Users can provide declarations and clauses for field access
-functions @samp{@var{Field}/1} and @samp{'@var{Field}:='/2},
+functions @samp{@var{field}/1} and @samp{'@var{field}:='/2},
overriding the compiler-generated default declarations and
clauses.
The compiler-generated field access functions can always
-be called using the functions @samp{'builtin @var{Field}'/1} and
- at samp{'builtin @var{Field}:='/2}. These functions may not be overridden
+be called using the functions @samp{'builtin @var{field}'/1} and
+ at samp{'builtin @var{field}:='/2}. These functions may not be overridden
by the user. They are visible only in the module containing the declaration
of the type containing the field --- client modules must always use the
user-supplied field access functions.
--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to: mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions: mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------
More information about the developers
mailing list