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-&gt;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-&gt;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-&gt;SUSPLISTNAME                e.g. X->inst
914        Vars-&gt;ATTRNAME:SUSPLISTNAME       e.g. X->fd:min
915        Vars-&gt;ATTRNAME:ARGINDEX           e.g. X->fd:(min of fd)
916        Vars-&gt;ATTRNAME:ARGLIST            e.g. X->fd:[min,max]
917        Vars-&gt;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