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) 2006 Cisco Systems, Inc. All Rights Reserved. 18% 19% Contributor(s): 20% 21% END LICENSE BLOCK 22 23:- comment(alias, "Advanced Control and Suspensions"). 24:- comment(summary, "Everything related to suspensions, priority- and data-driven control"). 25:- comment(categories, ["Built-In Predicates"]). 26 27:- tool(call_local / 1). 28:- tool(call_priority / 2). 29:- tool(insert_suspension / 3). 30:- tool(make_suspension / 3). 31:- tool(subcall / 2). 32:- tool(suspend / 3). 33:- tool(suspend / 4). 34 35:- comment(insert_suspension / 3, [ 36 summary:"Insert the suspension Susp into the Index'th suspension list of the current 37module's attribute for all attributed variables that occur in Term. 38 39", 40 amode:(insert_suspension(?,+,+) is det), 41 desc:html(" This predicate is used to insert a suspension into a suspension list in 42 an attribute of one or more attributed variables. Since Prolog does not allow to 43 insert new elements into a list in constant time, ECLiPSe provides this 44 predicate. It finds all attributed variables occurring in the term Term and for 45 each of them, it locates the attribute which corresponds to the current 46 module. This attribute must be a structure, otherwise an error is 47 raised, which means that the attribute has to be initialised before 48 calling insert_suspension/3. The Index'th argument of the attribute 49 structure is interpreted as a suspension list and the suspension Susp is 50 inserted at the beginning of this list. 51<P> 52"), 53 args:["Term" : "Any Prolog term.", "Susp" : "A suspension.", "Index" : "An integer."], 54 exceptions:[ 55 4 : "Susp or Index is not instantiated.", 56 5 : "Susp is not a suspension.", 57 5 : "Index is not an integer.", 58 6 : "The attribute of a variable in Term is a structure whose arity is less than Index.", 59 270 : "The current module has no declared variable attribute.", 60 271 : "The attribute of a variable in Term is uninstantiated or it is not a structure.", 61 271 : "The suspension list in the attribute of a variable in Term is neither a list nor a free variable, or it contains an element which is not a suspension." 62 ], 63 eg:" 64[eclipse 1]: meta_attribute(eclipse,[]). 65Yes (0.01s cpu) 66 67[eclipse 2]: Att = att(_, hello), init_suspension_list(1, Att), 68 add_attribute(X, Att), make_suspension(true, 1, S), 69 insert_suspension(X, S, 1). 70 71Att = att(['SUSP-_306-susp'], hello) 72X = X 73S = 'SUSP-_306-susp' 74 75Delayed goals: 76 true 77Yes (0.00s cpu) 78", 79 see_also:[insert_suspension / 4, make_suspension / 3, 80 meta_attribute / 2, enter_suspension_list / 3]]). 81 82:- comment(insert_suspension / 4, [ 83 summary:"Insert the suspension Susp into the Index'th suspension list of the 84attribute Module for all attributed variables that occur in Term. 85 86", 87 amode:(insert_suspension(?,+,+,+) is det), 88 desc:html(" This predicate is used to insert a suspension into a suspension list in 89 an attribute of one or more attributed variables. Since Prolog does not allow to 90 insert new elements into a list in constant time, ECLiPSe provides this 91 predicate. It finds all attributed variables occurring in the term Term and for 92 each of them, it locates the attribute with the name Module. This 93 attribute must be a structure, otherwise an error is raised, which means 94 that the attribute has to be initialised before calling 95 insert_suspension/3. The Index'th argument of the attribute structure 96 is interpreted as a suspension list and the suspension Susp is inserted 97 at the beginning of this list. 98 99<P> 100"), 101 args:["Term" : "Any Prolog term.", "Susp" : "A suspension.", "Index" : "An integer.", "Module" : "An atom."], 102 exceptions:[ 103 4 : "Susp or Index is not instantiated.", 104 5 : "Susp is not a suspension.", 105 5 : "Index is not an integer.", 106 6 : "The attribute of a variable in Term is a structure whose arity is less than Index.", 107 270 : "The current module has no declared variable attribute.", 108 271 : "The attribute of a variable in Term is uninstantiated or it is not a structure.", 109 271 : "The suspension list in the attribute of a variable in Term is neither a list nor a free variable, or it contains an element which is not a suspension." 110 ], 111 eg:" 112[eclipse 1]: meta_attribute(myatt,[]). 113Yes (0.01s cpu) 114 115[eclipse 2]: Att = att(_, hello), init_suspension_list(1, Att), 116 add_attribute(X, Att, myatt), make_suspension(true, 1, S), 117 insert_suspension(X, S, 1, myatt). 118 119Att = att(['SUSP-_309-susp'], hello) 120X = X 121S = 'SUSP-_309-susp' 122 123Delayed goals: 124 true 125Yes (0.00s cpu) 126", 127 see_also:[insert_suspension / 3, make_suspension / 3, 128 meta_attribute / 2, enter_suspension_list / 3]]). 129 130:- comment(get_suspension_data / 3, [ 131 summary:"Access properties of suspended goals. 132 133", 134 amode:(get_suspension_data(?,+,-) is semidet), 135 desc:html(" This built-in is used to access the contents of the abstract suspension 136 data type. If applied to an already executed (dead) suspension it fails, 137 unless the state information is requested. 138 139<P> 140 The accessible properties of a suspension are: 141 142<P> 143<PRE> 144 Name Type Value 145 ------------------------------------------------------------- 146 goal Term Suspended goal 147 module Atom Context module 148 qualified_goal Atom:Term Lookup module and goal 149 priority Integer Waking priority 150 invoc Integer Invocation number (debugging) 151 state Integer 0 (sleeping), 1 (scheduled), 2 (dead) 152</PRE> 153 Note that a suspension is not a standard logical data structure and can 154 only be manipulated in a restricted way. In particular, a suspension 155 cannot be printed (e.g. using writeq/1,2) and then read back, giving a 156 term identical to the one that was printed. 157 158<P> 159"), 160 args:["Susp" : "A suspension or variable.", "Name" : "An atom.", "Value" : "A variable."], 161 fail_if:"Fails if Susp is uninstantiated or if the suspension is already dead and Name is not 'state'", 162 exceptions:[4 : "Name is not instantiated.", 5 : "Susp is not a suspension.", 5 : "Name is instantiated but not an atom.", 6 : "Name is not the name of a suspension property."], 163 eg:" 164 [eclipse 4]: make_suspension(writeln(hello), 5, S), 165 get_suspension_data(S, priority, P), 166 get_suspension_data(S, goal, G), 167 get_suspension_data(S, module, M), 168 get_suspension_data(S, qualified_goal, QG), 169 get_suspension_data(S, invoc, I), 170 get_suspension_data(S, state, Z). 171 172 P = 5 173 G = writeln(hello) 174 M = eclipse 175 QG = eclipse : writeln(hello) 176 I = 0 177 S = 'SUSP-_162-susp' 178 Z = 0 179 Delayed goals: 180 writeln(hello) 181 yes. 182 183 [eclipse 2]: suspend(writeln(hello), 3, X->inst, S), 184 get_suspension_data(S, state, Z0), 185 call_priority((X=1,true,get_suspension_data(S, state, Z1)), 2), 186 get_suspension_data(S, state, Z2). 187 hello 188 189 Z0 = 0 190 X = 1 191 Z1 = 1 192 S = 'SUSP-_161-dead' 193 Z2 = 2 194 yes. 195 196 197 198", 199 see_also:[delayed_goals / 1, kill_suspension / 1, make_suspension / 3, get_priority / 1, call_priority / 2, suspend / 3, suspensions / 1, current_suspension / 1, set_suspension_data / 3]]). 200 201:- comment(attach_suspensions / 2, [ 202 summary:"Insert the suspensions Susps into the suspension list of the symbolic 203trigger Trigger. 204 205", 206 amode:(attach_suspensions(+,++) is det), 207 desc:html(" This predicate is used to insert one or more suspensions into a 208 suspension list which is associated to the symbolic name Trigger. 209 This name can be an arbitrary atom. 210 211<P> 212 The suspensions will be woken by a corresponding invocation of 213 schedule_suspensions/1. 214 215<P> 216"), 217 args:["Trigger" : "An atom.", "Susps" : "A suspension or list of suspensions."], 218 exceptions:[4 : "Susps or Trigger is not instantiated.", 5 : "Susps is not a suspension or list.", 5 : "Trigger is not an atom."], 219 eg:" 220 221 222", 223 see_also:[insert_suspension / 4, make_suspension / 3, suspend / 3, suspend / 4, schedule_suspensions / 1, (demon) / 1]]). 224 225:- comment(call_priority / 2, [ 226 summary:"Execute Goal with priority Priority. 227 228", 229 amode:call_priority(+,+), 230 desc:html(" All goals in ECLiPSe execute under a certain priority. An execution 231 can only be interrupted by the waking of a goal with a higher 232 priority. Priorities are most relevant in data-driven algorithms, 233 to specify that certain goals must do their work before others 234 can meaningfully execute. 235 236<P> 237 Priorities range from 1 (most urgent) to 12 (least urgent). The 238 toplevel goal of an execution always runs at the lowest priority (12). 239 240<P> 241 call_priority/2 runs a goal at a given priority. If this priority 242 is higher than the one under which call_priority was invoked, 243 the goal executes immediately, but will be less interruptable 244 by woken goals. If the specified priority is lower, the execution 245 of goal will be effectively deferred until there are no more urgent 246 goal present. 247 248<P> 249 Note that woken goals automatically execute under their associated 250 run_priority (which is a property of the predicate that is being invoked). 251 This is equivalent to a call_priority/2, therefore call_priority/2 is 252 usually not needed inside woken predicates. 253 254<P> 255 Warning: Although it is possible to write programs that only work 256 correctly under a particular priority ordering, such practice is 257 strongly discouraged. Priorities should only affect efficiency, 258 never correctness. 259 260<P> 261"), 262 args:["Goal" : "Atom or compound term.", "Priority" : "A small integer."], 263 resat:"Resatisfiable if Goal is resatisfiable", 264 fail_if:"Fails if Goal fails", 265 exceptions:[4 : "Goal or Priority is not instantiated.", 5 : "Goal is not an atom or a compound term, or Priority is not an integer.", 24 : "Priority is not a number."], 266 eg:" 267 [eclipse 1]: [user]. 268 p :- call_priority(writeln(hello),8), writeln(world). 269 270 user compiled traceable 136 bytes in 0.00 seconds 271 yes. 272 [eclipse 10]: call_priority(p,5). 273 world 274 hello 275 yes. 276 [eclipse 11]: call_priority(p,10). 277 hello 278 world 279 yes. 280 [eclipse 12]: call_priority(p,8). 281 hello 282 world 283 yes. 284 285 286 287", 288 see_also:[get_priority / 1, make_suspension / 3, suspend / 3, suspend / 4, set_suspension_data / 3]]). 289 290:- comment(current_suspension / 1, [ 291 summary:"Susp is a live (sleeping or scheduled) suspension. 292 293", 294 amode:(current_suspension(-) is nondet), 295 amode:(current_suspension(+) is semidet), 296 desc:html(" Suspensions in ECLiPSe go through several stages: They are created, 297 attached to variables or symbolic triggers, later scheduled for 298 execution, and finally executed. 299 300<P> 301 current_suspension/1 nondeterministically enumerates all current 302 suspensions. They may be either sleeping or already scheduled 303 for execution. It does not return any dead suspensions. 304 305<P> 306 Note: Please do not use this predicate if you need all suspensions. 307 Use suspensions/1 instead. 308 309<P> 310"), 311 args:["Susp" : "A variable."], 312 fail_if:"Fail is there are no suspensions or if Susp is a dead suspension", 313 eg:" 314[eclipse 6]: suspend(writeln(a), 3, X->inst), 315 suspend(writeln(b), 5, Y->inst), 316 current_suspension(S), 317 get_suspension_data(S, goal, G). 318 319X = X 320Y = Y 321S = 'SUSP-_393-susp' 322G = writeln(b) 323 324 325Delayed goals: 326 writeln(a) 327 writeln(b) 328More (0.00s cpu) ? ; 329 330X = X 331Y = Y 332S = 'SUSP-_374-susp' 333G = writeln(a) 334 335 336Delayed goals: 337 writeln(a) 338 writeln(b) 339More (0.00s cpu) ? ; 340 341No (0.01s cpu) 342", 343 see_also:[delayed_goals / 1, make_suspension / 3, kill_suspension / 1, schedule_suspensions / 1, schedule_suspensions / 2, suspend / 3, suspend / 4, suspensions / 1, get_suspension_data / 3]]). 344 345:- comment(get_priority / 1, [ 346 summary:"Get the priority of the currently executing goal. 347 348", 349 amode:(get_priority(-) is det), 350 desc:html(" All goals in ECLiPSe execute under a certain priority. An execution 351 can only be interrupted by the waking of a goal with a higher 352 priority. Priorities are most relevant in data-driven algorithms, 353 to specify that certain goals must do their work before others 354 can meaningfully execute. 355 356<P> 357 Priorities range from 1 (most urgent) to 12 (least urgent). The 358 toplevel goal of an execution always runs at the lowest priority (12). 359 360<P> 361 Warning: Although it is possible to write programs that only work 362 correctly under a particular priority ordering, such practice is 363 strongly discouraged. Priorities should only affect efficiency, 364 never correctness. 365 366<P> 367"), 368 args:["Priority" : "A variable."], 369 exceptions:[24 : "Priority is neither variable nor number."], 370 eg:" 371 [eclipse 1]: get_priority(P). 372 P = 12 373 yes. 374 375 [eclipse 2]: [user]. 376 p :- get_priority(P), writeln(prio=P). 377 378 user compiled traceable 120 bytes in 0.00 seconds 379 yes. 380 [eclipse 3]: suspend(p, 5, X->inst), X=1. 381 prio = 5 382 X = 1 383 yes. 384 385 386 387", 388 see_also:[call_priority / 2, make_suspension / 3, suspend / 3, suspend / 4, set_suspension_data / 3]]). 389 390:- comment(init_suspension_list / 2, [ 391 summary:"Initialise the argument position Position within the structure 392Attribute with an empty suspension list. 393 394", 395 amode:(init_suspension_list(+,+) is det), 396 desc:html(" This predicate is used to initialise a suspension list within 397 an attribute structure. Suspension lists should be regarded an 398 opaque data structure and only be accessed and manipulated 399 by the set of primitives provided for this purpose. 400 401<P> 402"), 403 args:["Position" : "Integer indicating the position of the suspension list.", "Attribute" : "Compound term, typically a variable's attribute."], 404 exceptions:[4 : "Position or Attribute is not instatiated.", 5 : "Position is not an integer.", 5 : "Attribute is not a structure.", 6 : "Attribute does not have a Position'th argument."], 405 eg:" 406 407 408 409", 410 see_also:[insert_suspension / 3, insert_suspension / 4, 411 schedule_suspensions / 2, merge_suspension_lists / 4, 412 enter_suspension_list / 3]]). 413 414:- comment(kill_suspension / 1, [ 415 summary:"Kill the suspended goal represented by Susp, i.e. treat it as if it had 416been woken. 417 418", 419 amode:(kill_suspension(?) is det), 420 desc:html(" The suspended goal represented by Susp is killed, and the suspension is 421 marked as now representing a woken goal. If the suspension was already 422 marked as woken, kill_suspension/1 just succeeds. If called with a 423 variable, it succeeds as well which is useful when writing demon 424 predicates that might not have a suspension the first time they are 425 invoked. 426 427<P> 428 Note that a suspension is not a standard Prolog data structure and can 429 only be manipulated in a restricted way. 430 431<P> 432"), 433 args:["Susp" : "A suspension or variable."], 434 exceptions:[5 : "Susp is not a suspension."], 435 eg:" 436[eclipse 1]: suspend(writeln(hello), 3, X->inst, Susp), 437 X=1. % wakes 438hello 439 440Susp = 'SUSP-_299-dead' 441X = 1 442Yes (0.00s cpu) 443 444 445[eclipse 2]: suspend(writeln(hello), 3, X->inst, Susp), 446 kill_suspension(Susp), 447 X=1. % no effect 448 449Susp = 'SUSP-_308-dead' 450X = 1 451Yes (0.00s cpu) 452", 453 see_also:[(demon) / 1, make_suspension / 3, get_suspension_data / 3, attach_suspensions / 2, insert_suspension / 3, insert_suspension / 4]]). 454 455:- comment(make_suspension / 3, [ 456 summary:"Make Goal a suspended goal", 457 amode:(make_suspension(+,+,-) is det), 458 desc:html("\ 459 The goal Goal is made a suspended goal, i.e. it enters the suspended 460 part of the resolvent and shows up as a delayed goal. When the debugger 461 is on, a DELAY port is generated. 462<P> 463 A suspension can be in three states: 464<PRE> 465 State Printed as 466 --------------------------------- 467 sleeping 'SUSP-_123-susp' 468 scheduled 'SUSP-_123-sched' 469 dead 'SUSP-_123-dead' 470</PRE> 471<P> 472 The Prio argument determines the priority with which the Goal will be 473 scheduled when woken. It can be a positive number between 1 and 12, 474 or zero, in which case the priority defaults to the priority setting 475 of the predicate which is called in Goal. 476<P> 477 Note that a suspension is not a standard Prolog data structure and can 478 only be manipulated in a restricted way. In particular, a suspension is 479 not an atom although it gets printed by default in the form 480 'SUSP-_123-susp'. The only way to create a suspension is with 481 make_suspension/3,4, suspend/3,4 or by copying an existing suspension. 482 The contents of a suspension can only be retrieved using get_suspension_data/3. 483<P> 484"), 485 args:["Goal" : "A Prolog Goal.", "Prio" : "A small integer.", "Susp" : "A variable."], 486 exceptions:[ 487 4 : "Goal is not instantiated.", 488 5 : "Goal is not a callable term.", 489 5 : "Susp is not a variable.", 490 5 : "Prio is not an integer.", 491 6 : "Prio is not a valid priority.", 492 60 : "Goal refers to an undefined precedure." 493 ], 494 eg:" 495[eclipse 1]: make_suspension(writeln(hello), 1, S), suspensions(Ss). 496 497S = 'SUSP-_264-susp' 498Ss = ['SUSP-_264-susp'] 499 500Delayed goals: 501 writeln(hello) 502Yes (0.00s cpu) 503 504 505[eclipse 2]: make_suspension(true, 3, S), is_suspension(S), type_of(S,T). 506 507S = 'SUSP-_272-susp' 508T = goal 509 510 511Delayed goals: 512 true 513Yes (0.00s cpu) 514", 515 see_also:[suspend/3, delayed_goals / 1, insert_suspension / 4, is_suspension / 1, kill_suspension / 1, schedule_suspensions / 1, schedule_suspensions / 2, get_suspension_data / 3, set_flag/3, wake / 0]]). 516 517:- comment(make_suspension / 4, [ 518 summary:"Make Goal a suspended goal", 519 amode:(make_suspension(+,+,-,+) is det), 520 desc:html("<P> 521 This is equivalent to 522<PRE> 523 make_suspension(Goal, Prio, Susp)@Module 524</PRE> 525 which should be preferred. 526</P> 527"), 528 args:["Goal" : "A Prolog Goal.", "Prio" : "A small integer.", "Susp" : "A variable.", "Module" : "An atom."], 529 exceptions:[ 530 4 : "Goal is not instantiated.", 531 4 : "Module is not instantiated.", 532 5 : "Goal is not a callable term.", 533 5 : "Susp is not a variable.", 534 5 : "Prio is not an integer.", 535 5 : "Module is not an atom.", 536 6 : "Prio is not a valid priority.", 537 60 : "Goal refers to an undefined precedure." 538 ], 539 see_also:[make_suspension/3]]). 540 541:- comment(enter_suspension_list / 3, [ 542 summary:"Enter the suspension Susp into the suspension list at position Positiion within the structure Attribute.", 543 args: ["Position": "Integer indicating the position of the suspension list.", 544 "Attribute": "Compound term, typically a variable's attribute.", 545 "Susp": "A suspension" 546 547 ], 548 amode:(enter_suspension_list(+,+,+) is det), 549 desc:html("\ 550<P> 551 This predicate is used to add a suspension to a single suspension list. 552 The suspension list is expected in the Position'th argument of the 553 structure Attribute. This argument can be either an existing suspension 554 list, or a variable. If it is a variable, a new suspension list with 555 Susp will be created. 556</P><P> 557 The functionality is similar to insert_suspension/3, but while 558 enter_suspension_list/3 enters only into a single suspension list, 559 insert_suspension/3 finds all variables in a term and inserts a 560 suspension into the attribute structures of all those variables. 561</P><P> 562 Suspension lists should be regarded an opaque data structure and 563 only be accessed and manipulated by the set of primitives provided 564 for this purpose. 565</P> 566"), 567 eg:" 568[eclipse 1]: Att = att(_, hello), init_suspension_list(1, Att), 569 make_suspension(true, 3, S), enter_suspension_list(1, Att, S). 570 571Att = att(['SUSP-_286-susp'], hello) 572S = 'SUSP-_286-susp' 573 574Delayed goals: 575 true 576Yes (0.00s cpu) 577", 578 exceptions:[ 579 4 : "Attribute, Susp or Position not instantiated.", 580 5 : "Attribute is not a structure, or Susp not a suspension or Position is a non-integer number.", 581 6 : "Attribute's arity is less than Position, or Position is zero or less.", 582 24 : "Position is a non-number.", 583 271 : "The suspension list in Position of Attribute is neither a list nor a free variable, or it contains an element which is not a suspension." 584 ], 585 see_also: [insert_suspension / 3, insert_suspension / 4, schedule_suspensions / 2, init_suspension_list / 2]]). 586 587 588:- comment(merge_suspension_lists / 4, [ 589 summary:"Destructively merge the suspension list on Pos1 in structure Attr1 590into the suspension list on Pos2 in structure Attr2. 591 592", 593 amode:(merge_suspension_lists(+,+,+,+) is det), 594 desc:html(" This predicate is used to merge two suspension lists. The list 595 in Attr1 remains unaffected but the list in Attr2 is replaced 596 by the merge of the two lists. 597 598<P> 599 Suspension lists should be regarded an opaque data structure and 600 only be accessed and manipulated by the set of primitives provided 601 for this purpose. 602 603<P> 604"), 605 args:["Pos1" : "Integer indicating the position of the suspension list.", "Attr1" : "Compound term, typically a variable's attribute.", "Pos2" : "Integer indicating the position of the suspension list.", "Attr2" : "Compound term, typically a variable's attribute."], 606 exceptions:[4 : "Pos1, Pos2, Attr1 or Attr2 is not instatiated.", 5 : "Pos1 or Pos2 is not an integer.", 5 : "Attr1 or Attr2 is not a structure or has no suspension list on the indicated argument position.", 6 : "Attr1 or Attr2 does not have a Position'th argument."], 607 eg:" 608 609 610 611", 612 see_also:[insert_suspension / 3, insert_suspension / 4, 613 schedule_suspensions / 2, init_suspension_list / 2, 614 enter_suspension_list / 3]]). 615 616 617:- comment(notify_constrained / 1, [ 618 summary:"Notify the system that the given variable was constrained", 619 amode:(notify_constrained(?) is det), 620 desc:html("<P>\ 621 When an extension package recognizes that new constraints have been 622 imposed on a particular attributed variable, it must notify the system 623 about it, so that other packages (e.g. Propia) or system primitives 624 (e.g. guards) can deliver proper results. 625 </P><P> 626 The operational semantics is that the 'constrained' suspension list 627 of the given variable will be scheduled for waking. After calling 628 notify_constrained/1 (and possibly after scheduling further suspension 629 lists in one go) a call to wake/0 must be made in order to actually 630 execute the scheduled suspensions. 631 </P><P> 632 Although notify_constrained/1 can safely be called with a simple variable 633 or nonvariable argument, doing so has no effect and will simply succeed. 634 </P> 635"), 636 args:["Var" : "A variable or any term"], 637 see_also:[wake/0]]). 638 639 640:- comment(schedule_suspensions / 1, [ 641 summary:"Take the suspension list associated with the symbolic trigger 642Trigger and schedule them for execution. 643 644", 645 amode:(schedule_suspensions(+) is det), 646 desc:html(" Suspensions in ECLiPSe go through several stages: They are created, 647 attached to variables or symbolic triggers, later scheduled for execution, 648 and finally executed. 649 650<P> 651 The task of schedule_suspensions/1 is to take suspensions from the 652 global suspension list associated to the symbolic name Trigger, and 653 schedule them for execution. The suspensions are inserted into a 654 global priority list, according to their individual priority. A 655 subsequent wake/0 will then actually execute them. 656 657<P> 658 If no suspensions are associated to Trigger, schedule_suspensions/1 659 just succeeds and does nothing. 660 661<P> 662"), 663 args:["Trigger" : "An atom."], 664 eg:" 665[eclipse 1]: suspend(writeln(world), 2, trigger(hello)), 666 schedule_suspensions(hello), wake. 667world 668yes. 669 670 671 672 673", 674 see_also:[(demon) / 1, insert_suspension / 3, insert_suspension / 4, make_suspension / 3, get_suspension_data / 3, attach_suspensions / 2, trigger / 1, wake / 0]]). 675 676:- comment(schedule_suspensions / 2, [ 677 summary:"Take the suspension list on argument position Position within Attribute, 678and schedule them for execution. 679 680", 681 amode:(schedule_suspensions(+,+) is det), 682 desc:html(" Suspensions in ECLiPSe go through several stages: They are created, 683 attached to variables or symbolic triggers, later scheduled for execution, 684 and finally executed. 685 686<P> 687 The task of schedule_suspensions/2 is to take suspensions 688 from a suspension list and schedule them for execution. 689 The suspensions are put into a global priority list, according 690 to their individual priority. A subsequent wake/0 will then 691 actually execute them. 692 693<P> 694 As a side effect, the suspension list within Attribute is updated, 695 ie. suspensions which are no longer useful are removed destructively. 696 697<P> 698"), 699 args:["Position" : "Integer indicating the position of the suspension list.", "Attribute" : "Compound term, typically a variable's attribute with a suspension list in Position'th argument."], 700 exceptions:[4 : "Position or Attribute is not instatiated.", 5 : "Position is not an integer.", 5 : "Attribute is not a structure or it Position'th argument is not a list of suspensions.", 6 : "Attribute does not have a Position'th argument."], 701 eg:" 702[eclipse 1]: make_suspension(writeln(hello), 4, S), 703 make_suspension(writeln('hi there'), 2, T), 704 Attr = attr([S,T]), 705 schedule_suspensions(1, Attr), 706 wake. 707hi there 708hello 709 710S = 'SUSP-_306-dead' 711T = 'SUSP-_311-dead' 712Attr = attr([]) 713yes. 714 715[eclipse 2]: [user]. 716 :- demon(d/0). 717 d :- writeln(demon). 718 719user compiled traceable 68 bytes in 0.12 seconds 720 721yes. 722[eclipse 3]: make_suspension(d, 4, S), 723 make_suspension(writeln('hi there'), 2, T), 724 Attr = attr([S,T]), 725 schedule_suspensions(1,Attr), 726 wake. 727hi there 728demon 729 730S = 'SUSP-_304-susp' 731T = 'SUSP-_309-dead' 732Attr = attr(['SUSP-_304-susp']) 733 734Delayed goals: 735 d 736yes. 737", 738 see_also:[(demon) / 1, insert_suspension / 3, insert_suspension / 4, make_suspension / 3, get_suspension_data / 3, wake / 0]]). 739 740:- comment(unschedule_suspension / 1, [ 741 summary:"Undo the scheduling of a suspension, preventing the delayed goal from actually being executed", 742 amode:(unschedule_suspension(+) is det), 743 desc:html(" 744 Suspensions in ECLiPSe go through several stages: They are created, 745 attached to variables or symbolic triggers, later scheduled for execution, 746 and finally executed. This predicate affects suspensions that are in the 747 scheduled state, and causes them to pass into the executed state without 748 actually being executed. 749<P> 750 Normally, scheduling a suspension leads to the execution of its associated 751 goal, which in turn leads to the suspension passing either into the dead 752 state (normal goals), or back into the suspended state (demons). 753<P> 754 Under special circumstances, it may be known that exection of a 755 scheduled goal would not have any further effect, and in that case 756 unschedule_suspension/1 can be used to pretend that the execution 757 has already happened. 758<P> 759 One example is a propagator for a global constraint, which touches the 760 variables it delays on, and thus wakes itself. This self-waking is 761 redundant if it is known that the propagation algorithm computes all 762 consequences (i.e. a fixpoint) internally. Self-waking can the be 763 prevented by calling unschedule_suspension/1 just before the propagator 764 terminates. 765<P> 766 Another example is a binary constraint, implemented via two uni-directional 767 propagators: the propagator for one direction may redundantly wake the 768 reverse propagator. This can be prevented by unscheduling the respective 769 reverse propagator (whose suspension can be passed as an argument). Of 770 course the programmer has to be careful only to cancel truly redundant 771 execution. 772<P> 773 This predicate is mainly useful in connection with demons: these go 774 back to suspended state if they were currently scheduled. Non-demons 775 get killed if they were currently scheduled. Suspensions that are 776 not currently scheduled (supendede or already dead) are unaffected. 777<P> 778"), 779 args:["Susp" : "A suspension"], 780 exceptions:[4 : "Susp is not instatiated.", 781 5 : "Susp is not a suspension."], 782 eg:" 783:- demon prop/3. 784prop(X, Y, RevSusp) :- 785 writeln(prop(X,Y)), 786 unschedule_suspension(RevSusp). 787 788 789% Despite waking both goals, only the first one is executed: 790?- suspend(prop(X,Y,SB),0,X->inst,SF), 791 suspend(prop(Y,X,SF),0,Y->inst,SB), 792 [X,Y] = [1,2]. 793 794prop(1, 2) % only forward demon wakes 795 796 X = 1 797 Y = 2 798 Delayed goals: 799 prop(1, 2, 'SUSP-_752-susp') 800 prop(2, 1, 'SUSP-_734-susp') 801 Yes (0.00s cpu) 802 803 804?- suspend(prop(X,Y,SB),0,X->inst,SF), 805 suspend(prop(Y,X,SF),0,Y->inst,SB), 806 [Y,X] = [2,1]. 807 808prop(2, 1) % only backward demon wakes 809 810 X = 1 811 Y = 2 812 Delayed goals: 813 prop(1, 2, 'SUSP-_752-susp') 814 prop(2, 1, 'SUSP-_734-susp') 815 Yes (0.00s cpu) 816 817", 818 see_also:[(demon) / 1, make_suspension / 3, 819 schedule_suspensions/2, kill_suspension/1, 820 get_suspension_data / 3]]). 821 822:- comment(set_suspension_data / 3, [ 823 summary:"Modify properties of suspended goals. 824 825", 826 amode:(set_suspension_data(+,+,+) is det), 827 desc:html(" This built-in is used to modify fields of the abstract suspension 828 data type. The modifiable properties of a suspension are: 829 830<P> 831<PRE> 832Name Type Value 833------------------------------------------------------------- 834priority Integer Waking priority 835invoc Integer Invocation number (debugging) 836</PRE> 837 All modifications are undone on backtracking. Changes to the priority 838 only have an effect the next time the suspension is scheduled 839 (ie changing the priority of an already scheduled suspension has 840 no effect unless it is a demon which can become suspended again). 841 If Susp is a variable or a dead suspension, this predicate 842 silently succeeds, doing nothing. 843 844<P> 845 Note that a suspension is not a standard logical data structure and can 846 only be manipulated in a restricted way. In particular, a suspension 847 cannot be printed (e.g. using writeq/1,2) and then read back, giving a 848 term identical to the one that was printed. 849 850<P> 851"), 852 args:["Susp" : "A suspension or variable.", "Name" : "An atom.", "Value" : "An integer."], 853 exceptions:[4 : "Name or Value is not instantiated.", 5 : "Susp is instantiated, but not a suspension.", 5 : "Name is instantiated but not an atom.", 6 : "Name is not the name of a modifiable suspension property."], 854 eg:" 855 [eclipse 1]: make_suspension(writeln(hello),5,S), 856 set_suspension_data(S, priority, 2), 857 get_suspension_data(S, priority, P). 858 859 S = 'SUSP-_123-susp' 860 P = 2 861 Delayed goals: 862 writeln(hello) 863 yes. 864 865 866 :- demon d/2. 867 d(X, Susp) :- 868 ( var(S) -> % initial suspend 869 suspend(d(X, Susp), 5, X->constrained, Susp) 870 ; finished(X) -> % terminate 871 kill_suspension(Susp) 872 ; useful(X) -> % raise priority 873 set_suspension_data(Susp, priority, 4) 874 ; % lower priority 875 set_suspension_data(Susp, priority, 6) 876 ). 877 878 879 880 881", 882 see_also:[delayed_goals / 1, kill_suspension / 1, make_suspension / 3, get_suspension_data / 3, get_priority / 1, call_priority / 2, suspend / 3, suspensions / 1, current_suspension / 1, get_suspension_data / 3]]). 883 884:- comment(suspend / 3, [ 885 summary:"Suspend the Goal and wake it with priority Prio as soon as one of the 886conditions in CondList occurs.", 887 amode:(suspend(+,+,+) is det), 888 desc:html("\ 889 The specified goal Goal is suspended (a suspension is created as with 890 make_suspension/3) and attached to the trigger conditions given in CondList. 891 When any of the trigger conditions arise in the future, the goal is 892 going to be woken up. 893<P> 894 The Prio argument determines the priority with which the Goal will be 895 scheduled when woken. It can be a positive number between 1 and 12, 896 or zero, in which case the priority defaults to the priority setting 897 of the predicate which is called in Goal. (Note that this is the scheduling 898 priority which determines the order of execution; the priority under which 899 the woken goal is executed may be higher, and is determined by the 900 run_priority predicate property, see set_flag/3). 901<P> 902 CondList is a list of terms (or a single term) of the form Vars->Cond 903 or trigger(Atom). It specifies the conditions that will lead to the goal 904 being woken up. It is enough for one of the specified conditions to arise 905 in order for the goal to be woken. 906<P> 907 Vars->Cond is used to specify trigger conditions on variables. 908 Vars is an arbitrary term, and the suspension will be attached to all 909 the variables that occur in Vars. These trigger conditions correspond 910 to suspension lists inside of variables's attributes, and can be 911 written in a variety of forms: 912<PRE> 913 Vars->SUSPLISTNAME e.g. X->inst 914 Vars->ATTRNAME:SUSPLISTNAME e.g. X->fd:min 915 Vars->ATTRNAME:ARGINDEX e.g. X->fd:(min of fd) 916 Vars->ATTRNAME:ARGLIST e.g. X->fd:[min,max] 917 Vars->LISTOFCONDS e.g. X->[fd:min,inst] 918</PRE> 919<P> 920 There are 3 predefined suspension list names: 'inst' (for instantiation), 921 'bound' (instantiation, including aliasing to another variable) and 922 'constrained' (any constraining attribute modification). These all 923 belong to an attribute called 'suspend'. Others are defined by libaries, 924 and usually the attribute name is identical to the library name (e.g. fd). 925<P> 926 A specification of the form trigger(Atom) states that the goal should 927 be woken by a symbolic trigger, ie. by a matching invocation of the 928 built-in schedule_suspensions/1. The name of the trigger can be an 929 arbitrary atom. 930<P> 931 A variant suspend/4 of this predicate is available. It returns a handle 932 for the created suspension, which is useful for suspending demons. 933<P> 934 NOTE: it is possible to create a suspension that can never be woken, 935 e.g. by specifying a Vars-term without variables. 936<P> 937"), 938 args:["Goal" : "A callable term.", "Prio" : "An integer.", "CondList" : "A term of the form Vars->Cond or trigger(Atom) or a list of such terms."], 939 exceptions:[6 : "CondList is ill-formed."], 940 eg:" 941[eclipse 1]: suspend(writeln(hello), 2, X->inst). 942 943X = X 944 945Delayed goals: 946 writeln(hello) 947yes. 948[eclipse 2]: suspend(writeln(hello), 2, X->inst), 949 writeln(one), 950 X=1, % causes waking 951 writeln(two). 952one 953hello 954two 955 956X = 1 957yes. 958[eclipse 3]: suspend(writeln(X), 2, [X,Y]->bound), X=Y. 959X 960 961X = X 962Y = X 963yes. 964[eclipse 4]: suspend(writeln(world), 2, trigger(hello)), trigger(hello). 965world 966 967yes. 968", 969 see_also:[suspend / 4, make_suspension / 3, insert_suspension / 3, 970 attach_suspensions / 2, schedule_suspensions / 1, meta_attribute/2, set_flag/3]]). 971 972:- comment(suspend / 4, [ 973 summary:"Suspend the Goal and wake it with priority Prio as soon as one of the 974conditions in CondList occurs.", 975 amode:(suspend(+,+,+,-) is det), 976 desc:html("\ 977 The specified goal Goal is suspended, subject to the given trigger 978 conditions and priority, as with suspend/3. The only difference to 979 suspend/3 is that the Susp argument returns a handle for the created 980 suspension. This handle can, for example, be passed as an argument to 981 the suspended goal itself, which is useful for demon goals which need 982 to kill their own suspension under certain circumstances. 983<P> 984 See suspend/3 for details of arguments and operation. 985<P> 986"), 987 args:["Goal" : "A callable term.", "Prio" : "An integer.", 988 "CondList" : "A term of the form Vars->Cond or trigger(Atom) or a list of such terms.", 989 "Susp" : "A free variable used to return the created suspension."], 990 exceptions:[6 : "CondList is ill-formed."], 991 eg:" 992[eclipse]: suspend(writeln(hello), 2, X->inst, Susp), 993 get_suspension_data(Susp, goal, Goal), 994 get_suspension_data(Susp, module, Module). 995 996X = X 997Goal = writeln(hello) 998Susp = 'SUSP-_321-susp' 999Module = eclipse 1000 1001Delayed goals: 1002 writeln(hello) 1003yes. 1004 1005 1006[eclipse]: suspend(writeln(hello), 2, X->inst, Susp), 1007 kill_suspension(Susp), % killed before woken 1008 X=1. 1009 1010Susp = 'SUSP-_308-dead' 1011X = 1 1012yes. 1013 1014 1015 1016% A demon that wakes whenever X becomes more constrained 1017report(X) :- 1018 suspend(report(X, Susp), 1, X->constrained, Susp). 1019 1020:- demon(report/2). 1021report(X, Susp) :- 1022 ( var(X) -> 1023 writeln(constrained(X)) % implicitly re-suspend 1024 ; 1025 writeln(instantiated(X)), 1026 kill_suspension(Susp) % remove from the resolvent 1027 ). 1028", 1029 see_also:[(demon) / 1, make_suspension / 3, insert_suspension / 3, suspend / 3, attach_suspensions / 2]]). 1030 1031:- comment(suspensions / 1, [ 1032 summary:"Returns a list of all currently live (sleeping or scheduled) suspensions. 1033 1034", 1035 amode:(suspensions(-) is det), 1036 desc:html(" Suspensions in ECLiPSe go through several stages: They are created, 1037 attached to variables or symbolic triggers, later scheduled for execution, 1038 and finally executed. 1039 1040<P> 1041 suspension/1 returns a list of all currently live suspensions. 1042 They may be either sleeping or already scheduled for execution. 1043 It does not return any dead suspensions. 1044 1045<P> 1046 Note: If you are looking for one particular suspension, consider 1047 using current_suspension/1 instead. 1048 1049<P> 1050"), 1051 args:["Susps" : "A variable."], 1052 eg:" 1053 [eclipse 6]: suspend(writeln(a),3,X->inst), 1054 suspend(writeln(b),5,Y->inst), 1055 suspensions(S). 1056 1057 X = X 1058 Y = Y 1059 S = ['SUSP-_358-susp', 'SUSP-_376-susp'] 1060 1061 Delayed goals: 1062 writeln(a) 1063 writeln(b) 1064 yes. 1065 1066 1067 1068 1069", 1070 see_also:[current_suspension / 1, delayed_goals / 1, make_suspension / 3, kill_suspension / 1, schedule_suspensions / 1, schedule_suspensions / 2, suspend / 3, suspend / 4, get_suspension_data / 3]]). 1071 1072:- comment(wake / 0, [ 1073 summary:"Execute all scheduled suspensions whose priorities are higher than the current 1074one. 1075 1076", 1077 amode:wake, 1078 desc:html(" Suspensions in ECLiPSe go through several stages: They are 1079 created, attached to variables or symbolic triggers, later 1080 scheduled for execution, and finally executed. 1081 1082<P> 1083 When a suspension is scheduled for execution, it gets inserted 1084 into a global priority list where it is waiting for execution. 1085 This global priority list is then processed explicitly by the 1086 wake/0 predicate. It will execute, in order of priority, all scheduled 1087 suspensions that have priority higher than the current execution priority. 1088 The woken goals themselves will be executed under their specific 1089 run_priority, which may be higher than their scheduling priority. 1090 1091 This separation of scheduling and execution enables the proper 1092 handling of priorities: Low priority suspensions are not 1093 necessarily executed by the next wake/0, but possibly later 1094 when the current priority has become low enough. 1095 1096<P> 1097 The separation also allows to schedule a batch of suspension lists 1098 together before entering the priority-based execution scheme. 1099 1100<P> 1101 wake/0 should therefore be called in the following situations: 1102 1103 1. after new suspensions have been scheduled by one or several 1104 calls to schedule_suspensions/1,2 or notify_constrained/1. 1105 1106<P> 1107 2. whenever the current priority was lowered, since that may allow 1108 further scheduled goals to be executed. 1109 1110<P> 1111 Note that wake/0 is implicitly invoked after every sequence of 1112 meta_unify handlers and should thus not be called inside the handlers. 1113 1114<P> 1115"), 1116 resat:"Resatisfiable if a woken goal is resatisfiable", 1117 fail_if:"Fails if a woken goal fails", 1118 eg:" 1119[eclipse 4]: make_suspension(write(a), 1, S), 1120 schedule_suspensions(1, attr([S])), 1121 wake, write(b). 1122ab 1123S = 'SUSP-_280-dead' 1124yes. 1125[eclipse 5]: make_suspension(write(a), 1, S), 1126 schedule_suspensions(1, attr([S])), 1127 write(b), wake. 1128ba 1129S = 'SUSP-_280-dead' 1130yes. 1131", 1132 see_also:[make_suspension / 3, insert_suspension / 3, suspend / 3, suspend / 4, schedule_suspensions / 1, schedule_suspensions / 2, attach_suspensions / 2]]). 1133 1134:- comment(subcall / 2, [ 1135 summary:"Succeeds iff Goal succeeds and unifies Delayed_goals with a list of 1136remaining delayed goals. 1137 1138", 1139 amode:subcall(+,-), 1140 desc:html(" Calls the goal Goal. When Goal succeeds, Delayed_goals is unified with 1141 a list of goals that were delayed, but not resumed during execution of 1142 Goal. These goals, together with the variable bindings in Goal, can be 1143 regarded as a qualified answer to Goal. I.e. Goal is true under the 1144 condition that the conjunction of delayed goals is also true. 1145 1146<P> 1147 Note that, after exiting from subcall/2, the goals collected in 1148 Delayed_goals do no longer exist as delayed goals. 1149 1150<P> 1151"), 1152 args:["Goal" : "Atom or compound term.", "Delayed_goals" : "Variable or list."], 1153 resat:"Resatisfiable if Goal is resatisfiable", 1154 fail_if:"Fails if Goal fails", 1155 exceptions:[4 : "Goal is not instantiated.", 5 : "Goal is neither an atom nor a compound term.", 68 : "Goal is an undefined procedure."], 1156 eg:" 1157Success: 1158 [eclipse]: X > 0, subcall(X < 5, DG). 1159 1160 X = X 1161 DG = [X < 5] 1162 1163 Delayed goals: 1164 X > 0 1165 yes. 1166 [eclipse]: subcall( (X > 0, Y > 0, X = 3) , DG). 1167 1168 Y = Y 1169 X = 3 1170 DG = [Y > 0] 1171 yes. 1172 1173Fail: 1174 subcall(fail, _). 1175Error: 1176 subcall(Var, D). (Error 4). 1177 subcall(3, D). (Error 5). 1178 subcall(foo(a), D). (Error 68). 1179 1180 1181 1182", 1183 see_also:[call / 1, (@) / 2, (:) / 2, call_priority/2]]). 1184 1185:- comment(trigger / 1, [ 1186 summary:"Wake the suspensions associated with the symbolic trigger Trigger 1187until there are no more left. 1188 1189", 1190 amode:trigger(+), 1191 fail_if:"Fails if a woken goal fails", 1192 desc:html(" Suspensions in ECLiPSe go through several stages: They are created, 1193 attached to variables or symbolic triggers, later scheduled for execution, 1194 and finally executed. 1195 1196<P> 1197 The task of trigger/1 is to take suspensions from the global suspension 1198 list associated to the symbolic name Trigger and wake them. The 1199 suspensions are inserted into a global priority list, according to 1200 their individual priority, and then executed. Trigger/1 includes a 1201 call to wake/0 and is actually defined as 1202 <PRE> 1203 trigger(Trigger) :- 1204 schedule_suspensions(Trigger), 1205 wake. 1206 </PRE> 1207<P> 1208 If no suspensions are associated to Trigger, trigger/1 1209 just succeeds and does nothing. 1210 1211<P> 1212"), 1213 args:["Trigger" : "An atom."], 1214 eg:" 1215[eclipse 1]: suspend(writeln(world), 2, trigger(hello)), trigger(hello). 1216world 1217yes. 1218 1219 1220 1221 1222", 1223 see_also:[(demon) / 1, attach_suspensions / 2, make_suspension / 3, suspend / 3]]). 1224 1225 1226:- comment(current_trigger / 1, [ 1227 summary:"Succeeds if Trigger is a currently defined symbolic trigger.", 1228 1229 1230 desc:html("<P> 1231 Succeeds if Trigger is a currently defined symbolic trigger for 1232 suspensions (see trigger/1). If Trigger is a variable, the current 1233 triggers will be enumerated one by one via backtracking. 1234"), 1235 args:["Trigger": "An atom or variable."], 1236 amode:(current_trigger(-) is nondet), 1237 amode:(current_trigger(+) is semidet), 1238 fail_if: "Trigger is not a current trigger.", 1239 see_also: [trigger/1] 1240]). 1241 1242:- comment(delayed_goals_number / 2, [ 1243 summary:"Succeeds if Number is the number of goals delayed by the variable Var. 1244 1245", 1246 amode:(delayed_goals_number(?,-) is det), 1247 desc:html(" Unifies Number with the number of goals delayed by the variable Var. If 1248 Var is instantiated, Number is unified with 1000000. If Var is not 1249 instantiated and there are no goals delayed by it, Number is unified 1250 with 0. This predicate does not construct the list of delayed goals and 1251 hence it is faster than delayed_goals/2. Its purpose is to give each 1252 variable a weight corresponding to the number of constraints imposed on 1253 the variable to be able to select the most constrained one. It is 1254 assumed that one million constraints cannot be placed on any variable. 1255 1256<P> 1257"), 1258 args:["Var" : "Any term.", "Number" : "Integer or a variable."], 1259 eg:" 1260Success: 1261 % Make an intelligent permutation choosing 1262 % the most constrained variable. 1263 perm([], []). 1264 perm([Var|List], Values) :- 1265 delayed_goals_number(Var, C), 1266 maxval(List, Var, C, Chosen, RestVar), 1267 delete(Chosen, Values, RestVal), 1268 perm(RestVar, RestVal). 1269 1270 maxval(L, Chosen, 1000000, Chosen, L) :- !. 1271 maxval([], Chosen, _, Chosen, []). 1272 maxval([X|L], SoFar, MaxVal, Chosen, [V|Rest]) :- 1273 delayed_goals_number(X, C), 1274 (C =< MaxVal -> V = X, Next = SoFar, Max = MaxVal ; 1275 V = SoFar, Next = X, Max = C), 1276 maxval(L, Next, Max, Chosen, Rest). 1277 % the values are generated in the listed order 1278 [eclipse]: perm([A, B, C], [1,2,3]). 1279 1280 A = 1 1281 B = 2 1282 C = 3 More? (;) 1283 yes. 1284 1285 % B is more constrained than the others, and so 1286 % its value will be generated first. 1287 [eclipse]: B < 3, perm([A, B, C], [1,2,3]). 1288 1289 A = 2 1290 B = 1 1291 C = 3 More? (;) 1292 1293Fail: 1294 X > 0, delayed_goals_number(X, 0). 1295 1296 1297 1298", 1299 see_also:[delayed_goals / 1, delayed_goals / 2, subcall / 2]]). 1300 1301:- comment(delayed_goals / 1, [ 1302 summary:"Succeeds if GoalList is the list of all goals currently delayed. 1303 1304", 1305 amode:(delayed_goals(-) is det), 1306 desc:html(" Unifies GoalList with the list of all goals currently delayed. If there 1307 are no goals delayed, GoalList is unified with nil. The order of goals 1308 in the list is implementation-dependent. Note that if GoalList is nil, 1309 the system only checks if there are any delayed goals and it does not 1310 actually construct the list. 1311 1312<P> 1313"), 1314 args:["GoalList" : "List, nil or variable."], 1315 exceptions:[5 : "GoalList is instantiated but not to a list or nil."], 1316 eg:" 1317Success: 1318 [eclipse]: X > 0, delayed_goals(L). 1319 1320 X = _d89 1321 L = [_d89 > 0] 1322 1323 Delayed goals: 1324 _d89 > 0 1325 yes. 1326 [eclipse]: X > 0, delayed_goals([1 > 0]). 1327 1328 X = 1 1329 yes. 1330 1331Fail: 1332 X > 0, delayed_goals([]). 1333 1334Error: 1335 delayed_goals(X > 0). (Error 5). 1336 delayed_goals(0). (Error 5). 1337 1338 1339 1340", 1341 see_also:[delayed_goals / 2, delayed_goals_number / 2, subcall / 2]]). 1342 1343:- comment(delayed_goals / 2, [ 1344 summary:"Succeeds if GoalList is the list of all goals delayed by the variable Var. 1345 1346", 1347 amode:(delayed_goals(?,-) is det), 1348 desc:html(" Unifies GoalList with the list of all goals delayed by the variable Var. 1349 This list contains all goals that will be woken if the variable Var will 1350 be instantiated. If there are no such goals, e.g. when Var is not a 1351 variable, GoalList is unified with nil. 1352 1353<P> 1354"), 1355 args:["Var" : "Any term.", "GoalList" : "List or variable."], 1356 eg:" 1357Success: 1358 [eclipse]: X > 0, X < 5, delayed_goals(X, L). 1359 1360 X = _d103 1361 L = [_d103 > 0, _d103 < 5] 1362 1363 Delayed goals: 1364 _d103 > 0 1365 _d103 < 5 1366 yes. 1367 [eclipse]: X > 0, X = 1, delayed_goals(X, L). 1368 1369 X = 1 1370 L = [] 1371 yes. 1372Fail: 1373 X > 0, delayed_goals(X, []). 1374 1375 1376 1377", 1378 see_also:[delayed_goals / 1, delayed_goals_number / 2, subcall / 2]]). 1379 1380 1381:- comment(suspensions / 2, [ 1382 summary:"Retrieves a list of all suspensions attached to the variable Var.", 1383 amode:(suspensions(?,-) is det), 1384 desc:html("\ 1385 Retrieves all live suspensions attached to the variable Var, and 1386 returns them in a duplicate-free list SuspensionList. 1387<P> 1388 Note that this is a relatively expensive operation, involving collecting 1389 all suspensions lists from the variable's attributes via their respective 1390 suspensions-handlers, then removing duplicates and dead suspensions. 1391"), 1392 args:["Var" : "Any term.", "SuspensionList" : "List or variable."], 1393 eg:" 1394[eclipse 2]: suspend:(X>5), suspensions(X, S). 1395X = X 1396S = ['SUSP-_256-susp'] 1397Delayed goals: 1398 suspend : (X > 5) 1399yes. 1400 1401[eclipse 3]: suspensions(X, S). 1402X = X 1403S = [] 1404yes. 1405 1406[eclipse 4]: suspensions(12, S). 1407S = [] 1408yes. 1409", 1410 see_also:[suspensions/1, subcall/2, get_suspension_data / 3]]). 1411 1412 1413:- comment(attached_suspensions / 2, [ 1414 summary:"Retrieves a list of all suspensions attached to the symbolic trigger Trigger.", 1415 amode:(attached_suspensions(+,-) is det), 1416 desc:html("\ 1417 Retrieves all suspensions (dead or live) attached to the trigger Trigger, 1418 and returns them in SuspensionList. 1419<P> 1420 Note that you can use sort/2 to eliminate duplicates, and 1421 is_suspension/1 to filter out dead suspensions. 1422"), 1423 args:["Trigger" : "An atom", "SuspensionList" : "Variable or List."], 1424 eg:" 1425?- suspend(true, 3, trigger(hello)), attached_suspensions(hello, S). 1426S = ['SUSP-_207-susp'] 1427Delayed goals: 1428 true 1429Yes (0.00s cpu) 1430", 1431 see_also:[suspensions/1, suspensions/2, subcall/2, 1432 get_suspension_data / 3, sort/2, is_suspension/1]]). 1433