Coroutining
Coroutining delays goals until variables become sufficiently instantiated.
30.1 dif/2 — sound disequality
?- dif(X, a), member(X, [a, b, c]). % X = b ; X = c
?- dif(f(X, Y), f(1, 2)), X = 1. % residual: dif(Y, 2)30.2 freeze/2
?- freeze(X, (writeln(got(X)))), X = 5. % prints got(5)
?- freeze(X, X > 3), X = 2. % false
% Lazy infinite lists
nat_stream(N, [N|T]) :- freeze(T, (N1 is N + 1, nat_stream(N1, T))).
?- nat_stream(0, S), S = [A, B, C|_]. % A = 0, B = 1, C = 230.3 when/2
Conditions: nonvar(X), ground(T), ?=(X, Y) (decidable equality), , and ; combinations.
?- when(ground(X-Y), Z is X + Y), X = 1, Y = 2. % Z = 3
?- when((nonvar(A) ; nonvar(B)), writeln(woke)), B = x.30.4 Attributed variables (building your own constraints)
put_attr/3, get_attr/3, del_attr/2, attr_unify_hook/2, attribute_goals//1, copy_term/3 (with residual goals). All CLP libraries are built on attributed variables.
:- module(domain, [domain/2]).
:- use_module(library(ordsets)).
domain(X, Dom) :- var(Dom), !, get_attr(X, domain, Dom).
domain(X, List) :-
list_to_ord_set(List, Domain),
put_attr(Y, domain, Domain),
X = Y.
attr_unify_hook(Domain, Y) :- % called when the variable is unified
( get_attr(Y, domain, Dom2)
-> ord_intersection(Domain, Dom2, NewDomain),
( NewDomain == [] -> fail
; NewDomain = [Value] -> Y = Value
; put_attr(Y, domain, NewDomain)
)
; var(Y) -> put_attr(Y, domain, Domain)
; ord_memberchk(Y, Domain)
).
attribute_goals(X) --> { get_attr(X, domain, List) }, [domain(X, List)].
?- domain(X, [a, b]), domain(X, [b, c]). % X = b