ECLiPSe abstract structure notation provides a way to use structures with field names. It is intended to make programs more readable and easier to modify, without compromising efficiency (it is implemented by parse-time preprocessing).
A structure is declared by specifying a template like this
:- local struct( book(author, title, year, publisher) ).
Structures with the functor book/4 can then be written as
book{} book{title:'tom sawyer'} book{title:'tom sawyer', year:1886, author:twain}
which translate to the corresponding forms
book(_, _, _, _) book(_, 'tom sawyer', _, _) book(twain, 'tom sawyer', 1886, _)
This transformation is done by the parser, therefore it can be used in any context and is as efficient as using the structures directly.
The argument index of a field in a structure can be obtained using a term of the form
FieldName of StructName
For example, to access (i.e., unify) a single argument of a structure use arg/3 like this:
..., arg(year of book, B, Y), ...
which is translated into
..., arg(3, B, Y), ...
If a program is consistently written using the abstract structure notation (i.e., with {...} and of), then the struct-declaration can be modified (fields added or rearranged) without having to update the code anywhere else.
To construct an updated structure, i.e., a structure which is similar to an existing structure except that one or more fields have new values, use the update_struct/4 built-in, which allows you to do that without having to mention all the other field names in the structure.
The arity of a structure can be symbolically written using of/2 as follows:
property(arity) of StructName
For example,
?- printf("A book has %d fields%n", [property(arity) of book]). A book has 4 fields Yes.
Similarly, the whole StructName/Arity specification can be written as
property(functor) of StructName
which is used for the portray-declaration in the example below.
When structures are printed, they are not translated back into the abstract structure syntax by default. The reason this is not done is that this can be bulky if all fields are printed, and often it is desirable to hide some of the fields anyway.
A good way to control printing of big structures is to write customized portray-transformations for them, for instance
:- local portray(property(functor) of book, tr_book_out/2, []). tr_book_out(book{author:A,title:T}, no_macro_expansion(book{author:A,title:T})).
which will cause book/4 structures to be printed like
book{author:twain, title:tom sawyer}
while the other two arguments remain hidden.
Structures can be declared to contain other structures, in which case they inherit the base structure’s field names. Consider the following declarations:
:- local struct(person(name,address,age)). :- local struct(employee(p:person,salary)).
The employee structure contains a field p which is a
person structure.
Field names of the person
structure can now be used as if
they were field names of the employee structure:
[eclipse 1]: Emp = employee{name:john,salary:2000}. Emp = employee(person(john, _105, _106), 2000) yes.
Note that, as long as the abstract structure notation is used, the employee structure can be viewed either as nested or as flat, depending on what is more convenient in a given situation. In particular, the embedded structure can still be accessed as a whole:
[eclipse 1]: Emp = employee{name:john,age:30,salary:2000,address:here}, arg(name of employee, Emp, Name), arg(age of employee, Emp, Age), arg(salary of employee, Emp, Salary), arg(address of employee, Emp, Address), arg(p of employee, Emp, Person). Emp = employee(person(john, here, 30), 2000) Name = john Age = 30 Salary = 2000 Address = here Person = person(john, here, 30) yes.
The indices of nested structures expand into lists of integers rather than simple integers, e.g., age of employee expands into [1,3].
Structure declaration can be local to a module (when declared as above) or exported when declared as
:- export struct(...).
in the module.