[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