1% BEGIN LICENSE BLOCK 2% Version: CMPL 1.1 3% 4% The contents of this file are subject to the Cisco-style Mozilla Public 5% License Version 1.1 (the "License"); you may not use this file except 6% in compliance with the License. You may obtain a copy of the License 7% at www.eclipse-clp.org/license. 8% 9% Software distributed under the License is distributed on an "AS IS" 10% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 11% the License for the specific language governing rights and limitations 12% under the License. 13% 14% The Original Code is The ECLiPSe Constraint Logic Programming System. 15% The Initial Developer of the Original Code is Cisco Systems, Inc. 16% Portions created by the Initial Developer are 17% Copyright (C) 1996 - 2006 Cisco Systems, Inc. All Rights Reserved. 18% 19% Contributor(s): 20% 21% END LICENSE BLOCK 22 23% @(#)extmeta.tex 1.8 96/01/08 24% 25 26\chapter{Attributed Variables} 27%HEVEA\cutdef[1]{section} 28\label{attrvars} 29\label{metaterms} 30\index{attributed variables|(}\index{variable!attributed} 31 32\section{Introduction} 33The \defnotion{attributed variable} is a special \eclipse data type which 34represents a variable together with attached attributes. 35In the literature, attributed variables are sometimes referred to as 36``metaterms''.\index{metaterm|see{attributed variable}} 37The name \about{metaterm} originates from its application in meta-programming: 38for an object-level program, a metaterm looks like a variable, but for 39a meta-program the same variable is just a piece of data which, possibly 40together with additional meta-level information, forms the metaterm. 41 42The attributed variable is a powerful means to implement various extensions of 43the 44plain Prolog language. 45In particular, it allows the system's behaviour 46on unification to be customised. 47In most situations an attributed variable behaves like a normal 48variable, e.g., 49it can be unified with other terms and 50\bipref{var/1}{../bips/kernel/typetest/var-1.html} succeeds on it. 51The differences in comparison to a plain variable are: 52\begin{itemize} 53\item an attributed variable has a number of associated \emph{attributes}; 54\item the attributes are included in the module system; 55\item when an attributed variable occurs in the unification and in some 56built-in predicates, each attribute is processed by a user-defined 57\emph{handler}. 58\end{itemize} 59 60\section{Declaration} 61An attributed variable can have any number of attributes. 62The attributes are accessed by their name. 63Before an attribute can be created and used, it must be declared 64with the predicate 65\bipref{meta_attribute/2}{../bips/kernel/termmanip/meta_attribute-2.html}. 66The declaration has the format 67\begin{quote} 68\predspec{meta_attribute(\pattern{Name},~\pattern{HandlerList})} 69\end{quote} 70\about{Name} is an atom denoting the attribute name 71and usually it is the name of the module where this attribute 72is being created and used. 73\about{HandlerList} is a (possibly empty) list of handler specifications 74for this attribute (see Section \ref{metahandlers}). 75 76\vfill %<<<<<<<<<<<<<<<< 77 78\section{Syntax} 79 80{\samepage 81The most general attributed variable syntax is 82\begin{quote} 83\preddef{\pattern{Var}\{\pattern{Name_1}:\pattern{Attr_1},% 84~\pattern{Name_2}:\pattern{Attr_2},~\ldots,% 85~\pattern{Name_n}:\pattern{Attr_n}\}} 86\end{quote} 87where the syntax of \about{Var} is like that of a variable, 88\about{Name_i} 89are attribute names and 90\about{Attr_i} 91are the values of the corresponding attributes. 92} 93The expression \notation{Var\{Attr\}} is a shorthand for 94\notation{Var\{\pattern{Module}:Attr\}} where \about{Module} is the current 95module name. 96The former is called \defnotionni{unqualified} and the latter 97\defnotionni{qualified} attribute specification. 98\index{qualified attribute specification} 99\index{attribute!specification!qualified} 100\index{unqualified attribute specification} 101\index{attribute!specification!unqualified} 102As the attribute name is usually identical with the source module name, 103all occurrences of an attributed variable in the source module may use the 104unqualified 105specification. 106 107If there are several occurrences of the same attributed variable in a single 108term, 109only one occurrence is written with the attribute, 110the others just refer to the variable's name, 111e.g., 112\begin{quote} 113\begin{verbatim} 114p(X, X{attr:Attr}) 115\end{verbatim} 116\end{quote} 117or 118\begin{quote} 119\begin{verbatim} 120p(X{attr:Attr}, X) 121\end{verbatim} 122\end{quote} 123both describe the same term, which has two occurrences of a single attributed 124variable 125with attribute \notation{attr:Attr}. 126The following is a syntax error (even when the attributes are identical): 127\begin{quote} 128\begin{verbatim} 129p(X{attr:Attr}, X{attr:Attr}) 130\end{verbatim} 131\end{quote} 132 133 134\section{Creating Attributed Variables} 135A new attribute can be added to a variable 136using the tool predicate 137\begin{quote} 138\predspec{add_attribute(\pattern{Var}, \pattern{Attr})}.% 139\indextt{add_attribute/2} 140\end{quote} 141An attribute whose name is not the current module name 142can be added using 143\bipref{add_attribute/3}{../bips/kernel/termmanip/add_attribute-3.html} which 144is its tool 145body predicate (exported in \notation{sepia_kernel}). 146If \about{Var} is a free variable, it will be bound to a new attributed variable 147whose attribute corresponding to the current module is 148\about{Attr} and all its other attributes are free variables. 149If \about{Var} is already an attributed variable and its attribute is 150uninstantiated, 151it will be bound to \about{Attr}, otherwise the effect of this predicate 152will be the same as unifying \about{Var} with another attributed variable 153whose attribute corresponding to the current module is 154\about{Attr}. 155 156\section{Decomposing Attributed Variables} 157The attributes of an attributed variable can be accessed using one-way 158unification in a matching clause, e.g., 159\begin{quote} 160\begin{verbatim} 161 get_attribute(X{Name:Attribute}, A) :- 162 -?-> 163 A = Attribute. 164\end{verbatim} 165\end{quote} 166This clause succeeds only when the first argument is an attributed variable, 167and it binds 168\about{X} to the whole attributed variable and \about{A} to the attribute 169whose name is the instantiation of \about{Name}. 170Note that a normal (unification) clause can \emph{not} be used to decompose 171an attributed variable (it would create a new attributed variable and unify this 172with the caller 173argument, but the unification is handled by an attributed variable handler, see 174Section \ref{metahandlers}). 175 176\section{Attribute Modification} 177Often an extension must modify the data stored in the 178attribute to reflect changes in the computation. 179The usual Prolog way to do this is by reserving 180one argument in the attribute structure for this next value. 181before accessing the most recent attribute value this chain 182of values has to be dereferenced until a value is found whose 183link is still free. 184A perfect compiler should be able to detect that the older 185attribute values are no longer accessed and it would compile 186these modifications using destructive assignment. 187Current compilers are unfortunately not able to perform 188this optimization (some systems can reduce these chains 189during garbage collection, but until this occurs, 190the list has to be dereferenced for each access and update). 191To avoid performance loss for both attribute updating and 192access, {\eclipse} provides a predicate for explicit 193attribute update: 194\predspec{setarg(\pattern{I}, \pattern{Term}, \pattern{NewArg})} will update the 195\about{I}'th 196argument of \about{Term} to be \about{NewArg}. 197Its previous value will be restored on backtracking. 198%Although the use of this predicate does not corrupt the 199%declarative reading of the program (it is merely 200%a shorthad for the above described modification 201%using value links), we still recommed to use it with care, 202%because sometimes it might yield unexpected results. 203 204Libraries which define user-programmable extensions 205like, e.g., \libspec{fd} usually define predicates that 206modify the attribute or a part of it, so that an explicit 207use of the \bipref{setarg/3}{../bips/kernel/termmanip/setarg-3.html} predicate 208is not necessary. 209 210\section{Attributed Variable Handlers} 211\label{metahandlers} 212An attributed variable is a variable with some additional information 213which is ignored by ordinary \emph{object level} system predicates. 214\emph{Meta level} operations on attributed variables are handled by 215extensions which know 216the contents of their attributes and can specify the outcome 217of each operation. 218This mechanism is implemented using \defnotionni{attributed variable handlers}, 219\index{attributed variables!handlers}\index{handler} 220which are user-defined predicates invoked 221whenever an attributed variable occurs in one of the predefined 222operations. 223The handlers are specified in the attribute declaration 224\predspec{meta_attribute(\pattern{Name},~\pattern{HandlerList})}, the second 225argument 226is a list of handlers in the form 227\begin{quote} 228\begin{verbatim} 229[unify:UnifyHandler, test_unify:TUHandler, ...] 230\end{verbatim} 231\end{quote} 232Handlers for operations which are not specified or those that are 233\bipref{true/0}{../bips/kernel/control/true-0.html} are ignored and never 234invoked. 235If \about{Name} is an existing extension, the specified handlers 236replace the current ones. 237 238Whenever one of the specified operations detects an attributed variable, 239it will invoke all handlers that were declared for it 240and each of them receives either the whole attributed variable 241or its particular attribute as argument. 242The system does not check if the attribute that corresponds 243to a given handler is instantiated or not; this means 244that the handler must check itself if the attributed variable 245contains any attribute information or not. 246For instance, if an attributed variable \notation{X\{a:_, b:_, c:f(a)\}} 247is unified with the attributed variable \notation{Y\{a:_, b:_, c:f(b)\}}, 248the handlers for the attributes \notation{a} and \notation{b} should 249treat this as binding of two plain variables 250because their attributes were not involved. 251Only the handler for \notation{c} has any work to do here. 252The library \libspec{suspend} can be used as a template 253for writing attributed variable handlers. 254 255The following operations invoke attributed variable handlers: 256 257\begin{description} 258%-------------------------- 259\item [unify:]\handleridx{unify} 260 the usual unification. 261The handler procedure is 262\begin{quote} 263\predspec{% 264unify_handler(+\pattern{Term},~?\pattern{Attribute}~[,\pattern{SuspAttr}])} 265\end{quote} 266The first argument is the term that was unified with the attributed variable, 267it is either a non-variable or another attributed variable. 268The second argument is the contents of the attribute slot 269corresponding to the extension. Note that, at this point in execution, 270the orginal attributed variable no longer exists, because it has already 271been bound to \about{Term}. 272The optional third argument is the suspend-attribute of the former 273variable; it may be needed to wake the variable's 'constrained' suspension 274list. 275 276The handler's job is to determine whether the binding is allowed with 277respect to the attribute. This could for example involve checking whether 278the bound term is in a domain described by the attribute. 279For variable-variable bindings, typically the remaining attribute must 280be updated to reflect the intersection of the two individual attributes. 281In case of success, suspension lists inside the attributes may need to 282be scheduled for waking. 283 284If an attributed variable is unified with a standard variable, the variable is 285bound 286to the attributed variable and no handlers are invoked. 287If an attributed variable is unified with another attributed variable or a 288non-variable, 289the attributed variable is bound (like a standard variable) to the other term 290\emph{and} all handlers for the \notation{unify} operation are invoked. 291Note that several attributed variable bindings can occur simultaneously, 292e.g.\ during a head unification or 293during the unification of two compound terms. 294The handlers are only invoked at certain trigger points (usually before the 295next regular predicate call). Woken goals will start executing once all 296unify-handlers are done. 297 298%-------------------------- 299\item [test_unify:]\handleridx{test_unify} 300 a unifiability test which is not supposed 301to trigger constraints propagation. It is used 302by the \bipref{not_unify/2}{../bips/kernel/termcomp/not_unify-2.html} 303predicate. 304The handler procedure is 305\begin{quote} 306\predspec{test_unify_handler(+\pattern{Term}, ?\pattern{Attribute})} 307\end{quote} 308where the arguments are the same as for the unify handler. 309The handler's job is to determine whether \about{Attribute} allows 310unification with \about{Term} (not considering effects of woken goals). 311During the execution of the handler, the attributed variable may be bound 312to \about{Term}, however when all attribute handlers succeed, 313all bindings are undone again, and no waking occurs. 314 315\item [compare_instances:]\handleridx{compare_instances} 316 computation of instance, subsumption 317and variance relationship, as performed by the built-ins 318\bipref{compare_instances/3}{../bips/kernel/termcomp/compare_instances-3.html}, 319\bipref{instance/2}{../bips/kernel/termcomp/instance-2.html} and 320\bipref{variant/2}{../bips/kernel/termcomp/variant-2.html}. 321The handler procedure is 322\begin{quote} 323\predspec{instance_handler(-\pattern{Res},~?\pattern{TermL},~?\pattern{TermR})} 324\end{quote} 325and its arguments are similar to the ones of the 326\bipref{compare_instances/3}{../bips/kernel/termcomp/compare_instances-3.html} 327predicate. 328The handler is invoked with one or both of \about{TermL} and \about{TermR} being 329attributed variables. The task of the handler is to examine the two terms, 330and compute their instance relationship with respect to the extension 331attribute in question. The handler must 332bind \about{Res} to \notation{=} iff the terms are variants, 333\notation{<} iff \about{TermL} is a proper instance of TermR, or \notation{>} 334iff \about{TermR} is a proper instance of \about{TermL}) with respect to 335the attribute under consideration. If the terms are not unifiable with respect 336to this attribute, the handler must fail. 337 338Even though one of \about{TermL} and \about{TermR} is guaranteed to be 339an attributed variable, they might not have the particular attribute that 340the handler is concerned with. The handler must therefore be written to 341correctly deal with all combinations of an attributed (but potentially 342uninstantiated attribute) variable with any other term. 343 344 345\item [copy_term:]\handleridx{copy_term} 346 the handler is invoked by either 347\bipref{copy_term/2}{../bips/kernel/termmanip/copy_term-2.html} or 348\bipref{copy_term_vars/3}{../bips/kernel/termmanip/copy_term_vars-3.html}. 349The handler procedure is 350\begin{quote} 351\predspec{copy_handler(?\pattern{AttrVar},~?\pattern{Copy})} 352\end{quote} 353\about{AttrVar} is the attributed variable encountered in the 354copied term, \about{Copy} is its corresponding variable in the copy. 355All extension handlers receive the same arguments. 356This means that if the attributed variable should be copied as 357an attributed variable, the handler must check if \about{Copy} is still 358a free variable or if it was already bound to an attributed variable by a 359previous handler. 360 361\item [suspensions:]\handleridx{suspensions} 362 this handler is invoked by the 363\bipref{suspensions/2}{../bips/kernel/suspensions/suspensions-2.html} predicate 364to collect all the suspension lists inside the attribute. 365The handler call pattern is 366\begin{quote} 367\predspec{suspensions_handler(?\pattern{AttrVar},~-\pattern{ListOfSuspLists},% 368~-\pattern{Tail})} 369\end{quote} 370\about{AttrVar} is an attributed variable. The handler should bind 371\about{ListOfSuspLists} to a list containing all the attribute's 372suspension lists and ending with \about{Tail}. 373 374 375\item [delayed_goals_number:]\handleridx{delayed_goals_number} 376 handler is invoked by the 377\bipref{delayed_goals_number/2}{../bips/kernel/suspensions/delayed_goals_number-2.html} 378predicate. 379The handler call pattern is 380\begin{quote} 381\predspec{delayed_goals_number_handler(?\pattern{AttrVar},% 382~-\pattern{Number})} 383\end{quote} 384\about{AttrVar} is the attributed variable encountered in the 385term, \about{Number} is the number of delayed 386goals occurring in this attribute. 387Its main purpose is for the first-fail selection predicates, 388i.e., it should return the number of constraints imposed on 389the variable. 390 391\item [get_bounds:]\handleridx{get_bounds} 392 This handler is used by the predicate 393 \bipref{get_var_bounds/3}{../bips/kernel/termmanip/get_var_bounds-3.html} 394 to retrieve information about the lower and upper bound of a numeric 395 variable. 396 The handler should therefore only be defined if the attribute contains 397 that kind of information. The handler call pattern is 398 \begin{quote} 399\predspec{% 400get_bounds_handler(?\pattern{AttrVar},~-\pattern{Lwb},~-\pattern{Upb})} 401 \end{quote} 402 The handler is only invoked if the variable has the corresponding 403 (non-empty) attribute. 404 The handler should bind \about{Lwb} and \about{Upb} to numbers 405 (any numeric type) reflecting the attribute's information about lower 406 and upper bound of the variable, respectively. 407 If different attributes return different bounds information, 408 \bipref{get_var_bounds/3}{../bips/kernel/termmanip/get_var_bounds-3.html} 409 will return the intersection of these bounds. This can be empty 410 (\about{Lwb} $>$ \about{Upb}). 411 412\item [set_bounds:]\handleridx{set_bounds} 413 This handler is used by the predicate 414 \bipref{set_var_bounds/3}{../bips/kernel/termmanip/set_var_bounds-3.html} 415 to distribute information about the lower and upper bound of a numeric 416 variable to all its existing attributes. 417 The handler should therefore only be defined if the attribute can 418 incorporate this kind of information. The handler call pattern is 419 \begin{quote} 420\predspec{% 421set_bounds_handler(?\pattern{AttrVar},~+\pattern{Lwb},~+\pattern{Upb})} 422 \end{quote} 423 The handler is only invoked if the variable has the corresponding 424 (non-empty) attribute. 425 \about{Lwb} and \about{Upb} are the numbers that were passed to 426 \bipref{set_var_bounds/3}{../bips/kernel/termmanip/set_var_bounds-3.html}, 427 and the handler is expected to update its 428 own bounds representation accordingly. 429 430 431 432\item [print:]\handleridx{print} 433 attribute printing in 434\biprefni{write/1,2}{../bips/kernel/ioterm/write-1.html},% 435\indextt{write/1}\indextt{write/2} 436\biprefni{writeln/1,2}{../bips/kernel/ioterm/writeln-1.html},% 437\indextt{writeln/1}\indextt{writeln/2} 438\biprefni{printf/2,3}{../bips/kernel/ioterm/printf-2.html}% 439\indextt{printf/2}\indextt{printf/3} 440when the \notation{m} option is specified. 441The handler procedure is 442\begin{quote} 443\predspec{print_handler(?\pattern{AttrVar},~-\pattern{PrintAttr})} 444\end{quote} 445\about{AttrVar} is the attributed variable being printed, \about{PrintAttr} 446is the term which will be printed as a value for this attribute, 447prefixed by the attribute name. 448If no handler is specified for an attribute, or the print handler fails, 449the attribute will not be printed. 450 451\end{description} 452 453The following handlers are still supported for compatibility, 454but their use is not recommened: 455\begin{description} 456\item [pre_unify:]\handleridx{pre_unify} 457 this is another handler which can be invoked on 458normal unification, but it is called \emph{before} the unification 459itself occurs. 460The handler procedure is 461\begin{quote} 462\predspec{pre_unify_handler(?\pattern{AttrVar},~+\pattern{Term})} 463\end{quote} 464The first argument is the attributed variable to be unfied, 465the second argument is the term it is going to be unified with. 466This handler is provided only for compatibility with SICStus Prolog 467and its use is not recommended, because it is less efficient 468than the \notation{unify} handler and because its semantics is somewhat 469unclear, there may be cases where changes inside this handler 470may have unexpected effects. 471 472\item [delayed_goals:]\handleridx{delayed_goals} 473 this handler is superseded by the 474suspensions-handler, which should be preferred. If there is no suspensions- 475handler, this handler is invoked by the obsolete 476\bipref{delayed_goals/2}{../bips/kernel/suspensions/delayed_goals-2.html} 477predicate. 478The handler procedure is 479\begin{quote} 480\predspec{delayed_goals_handler(?\pattern{AttrVar},~?\pattern{GoalList},% 481~-\pattern{GoalCont})} 482\end{quote} 483\about{AttrVar} is the attributed variable encountered in the 484term, \about{GoalList} is an open-ended list of all delayed 485goals in this attribute and \about{GoalCont} is the 486tail of this list. 487 488\end{description} 489 490%-------------------------- 491\subsection{Printing Attributed Variables} 492\indextt{output_mode} 493The different output predicates treat attributed variables differently. 494The \bipref{write/1}{../bips/kernel/ioterm/write-1.html} predicate prints 495the attributes using the print-handlers, 496while \bipref{writeq/1}{../bips/kernel/ioterm/writeq-1.html} prints the whole 497attribute, so that the attributed variable 498can be read back. 499The \bipref{printf/2}{../bips/kernel/ioterm/printf-2.html} predicate has two 500options to be combined with 501the \notation{w} format: \notation{M} forces the whole attributed variable to be 502printed 503together with all its attributes in the standard format, so that 504it can be read back in. 505With the \notation{m} option the attributed variable is printed using the 506handlers 507defined for the \notation{print} operation. 508If there is only one handled attribute, the attributed variable is printed as 509\begin{quote} 510X\{Attr\} 511\end{quote} 512where \about{Attr} is the value obtained from the handler. 513If there are several handled attributes, all attributes are qualified 514like in 515\begin{quote} 516X\{a:A, b:B, c:C\}. 517\end{quote} 518A simple print handler can just return the attribute literally, like 519\begin{quote}\begin{verbatim} 520print_attr(_{Attr}, PrintAttr) ?- PrintAttr=Attr. 521\end{verbatim}\end{quote} 522{\samepage 523An attributed variable \notation{X\{m:a\}} with \notation{print} handler 524\predspec{print_attr/2} 525for the m-attribute, can thus be printed in different ways, e.g., 526\footnote{The attribute \notation{suspend} is always present and defined 527by system coroutining.} 528\begin{quote} 529\begin{verbatim} 530printf("%w", [X{m:a}]) or write(X{m:a}): X 531printf("%vMw", [X{m:a}]) or writeq(X{m:a}): _g246{suspend : _g242, m : a} 532printf("%mw", [X{m:a}]): X{a} 533printf("%Mw", [X{m:a}]): X{suspend : _g251, m : a} 534printf("%Vmw", [X{m:a}]): X_g252{a} 535\end{verbatim} 536\end{quote} 537} 538 539\index{macro!write} 540Write macros for attributed variables are not allowed because one extension 541alone 542should not decide whether the other attributes will be printed or not. 543 544\section{Built-Ins and Attributed Variables} 545\begin{description} 546\item[free(?\pattern{Term})]\indextt{free/1} 547This type-checking predicate succeeds iff its argument is an 548ordinary free variable, it fails if it is an attributed variable. 549 550\item[meta(?\pattern{Term})]\indextt{meta/1} 551This type-checking predicate succeeds iff its argument is an attributed 552variable. 553For other type testing predicates an attributed variable behaves like a 554variable. 555\end{description} 556 557\section{Examples of Using Attributed Variables} 558\subsection{Variables with Enumerated Domains} 559As an example, let us implement variables of enumerable types 560using attributes. 561We choose to represent these variable as attributed variables 562whose attribute is 563a \notation{enum/1} structure with a list holding the values the variable may 564take, e.g., 565\begin{quote} 566\begin{verbatim} 567X{enum([a,b,c])} 568\end{verbatim} 569\end{quote} 570 571We have to specify now what should happen when such a variable is 572bound. This is done by writing a handler for the \notation{unify} operation. 573The predicate \predspec{unify_enum/2} defined below is this 574handler. 575Its first argument is the value that the attributed variable has been bound to, 576the second is the attribute that the bound attributed variable had 577(keep in mind that the system has already bound the attributed variable to the 578new value). We distinguish two cases: 579\begin{itemize} 580\item 581First, the attributed variable has been 582bound to another attributed variable (1st clause of \predspec{unify_enum/2}). 583In this case, we form the intersection between the two lists 584of admissible values. If it is empty, we fail. 585If it contains exactly one value, we can instantiate the remaining 586attributed variable with this value. 587Otherwise, we bind it to a new attributed variable whose attribute represents 588the remaining admissible values. 589 590\item 591Second, when the attributed variable has been bound to a non-variable, the 592task that remains for the handler is merely to check if this binding 593was admissible (second clause of \predspec{unify_enum/2}). 594\end{itemize} 595 596\begin{quote} 597\begin{verbatim} 598[eclipse 2]: module(enum). 599warning: creating a new module in module(enum) 600[enum 3]: [user]. 601:- meta_attribute(enum, [unify:unify_enum/2, print:print_enum/2]). 602:- import setarg/3 from sepia_kernel. 603 604% unify_enum(+Term, Attribute) 605unify_enum(_, Attr) :- 606 /*** ANY + VAR ***/ 607 var(Attr). % Ignore if no attribute for this extension 608unify_enum(Term, Attr) :- 609 compound(Attr), 610 unify_term_enum(Term, Attr). 611 612unify_term_enum(Value, enum(ListY)) :- 613 nonvar(Value), % The attributed variable was instantiated 614 /*** NONVAR + META ***/ 615 memberchk(Value, ListY). 616unify_term_enum(Y{AttrY}, AttrX) :- 617 -?-> 618 unify_enum_enum(Y, AttrX, AttrY). 619 620unify_enum_enum(_, AttrX, AttrY) :- 621 var(AttrY), % no attribute for this extension 622 /*** VAR + META ***/ 623 AttrX = AttrY. % share the attribute 624unify_enum_enum(Y, enum(ListX), AttrY) :- 625 nonvar(AttrY), 626 /*** META + META ***/ 627 AttrY = enum(ListY), 628 intersection(ListX, ListY, ListXY), 629 ( ListXY = [Val] -> 630 Y = Val 631 ; 632 ListXY \= [], 633 setarg(1, AttrY, ListXY) 634 ). 635 636print_enum(_{enum(List)}, Attr) :- 637 -?-> 638 Attr = List. 639 user compiled traceable 1188 bytes in 0.03 seconds 640 641yes. 642[enum 4]: A{enum([yellow, blue, white, green])} 643 = B{enum([orange, blue, red, yellow])}. 644 645A = B = A{[blue, yellow]} 646yes. 647[enum 5]: A{enum([yellow, blue, white, green])} 648 = B{enum([orange, blue, red, black])}. 649 650A = B = blue 651yes. 652[enum 6]: A{enum([yellow, blue, white, green])} = white. 653 654A = white 655yes. 656[enum 7]: A{enum([yellow, blue, white, green])} = red. 657 658no (more) solution. 659 660\end{verbatim} 661\end{quote} 662 663Some further remarks on this code: 664\index{matching} 665\index{pattern matching} 666\index{unification!pattern matching} 667The second clause of \predspec{unify_term_enum/2} 668is a \emph{matching clause}, as indicated 669by the \notation{-?->} guard. 670A matching clause is the only way to decompose an attributed variable. 671Note that this clause matches only calls that have an attributed variable 672with nonempty \notation{enum} attribute on the 673first argument position. 674 675\vfill %<<<<<<<<<<<<<<<<<<<<<<<< 676 677\section{Attribute Specification} 678The structures notation (see section~\ref{chapstruct}) 679is used to define 680and access variable attributes and their arguments. 681This makes the code independent of the number of attributes 682and positions of their arguments. 683Wherever appropriate, the libraries described in this document 684describe their attributes in this way, e.g., 685\begin{quote} 686\notation{suspend\{inst:I, constrained:C, bound:B\}} 687\end{quote} 688says that the structure name is \notation{suspend} and that 689it has (at least) three arguments with the corresponding names.% 690\index{attributed variables|)} 691 692%HEVEA\cutend 693 694 695