According to
Wikipedia, 
"Well Founded Semantics is one definition of how we can make 
conclusions from a set of logical rules". Well Founded Semantics (WFS) 
defines a three valued logic representing true,
false and something that is neither true or false. This latter 
value is often referred to as bottom, undefined or
unknown. SWI-Prolog uses undefined/0.
Well Founded Semantics allows for reasoning about programs with 
contradictions or multiple answer sets. It allows for obtaining 
true/false results for literals that do not depend on the sub program 
that has no unambiguous solution, propagating the notion of
undefined to literals that cannot be resolved otherwise and 
obtaining the residual program that expresses why an answer is 
not unambiguous.
The notion of Well Founded Semantics is only relevant if the 
program uses negation as implemented by tnot/1. 
The argument of
tnot/1, 
as the name implies, must be a goal associated with a tabled predicate 
(see table/1). 
In a nutshell, resolving a goal that implies
tnot/1 
is implemented as follows:
Consider the following partial body term:
        ...,
        tnot(p),
        q.
- If p has an unconditional answer in its table, fail.
- Else, delay the negation. If an unconditional answer 
arrives at some time, resume with failure.
- If at the end of the traditional tabled evaluation we can still not 
decide on p, execute the continuation (q 
above) while maintaining the delay list set to
tnot(p). If executing the continuation results in an answer 
for some tabled predicate, record this answer as a
conditional answer, in this case with the conditiontnot(p).
- If a conditional answer is added to a table, it is propagated to its
followers, say f, adding the pair {f,answer} 
to the delay list. If this leads to an answer, the answer is conditional 
on this pair.
- After the continuations of all unresolved tnot/1 
calls have been executed the various tables may have conditional answers 
in addition to normal answers.
- If there are negative literals that have neither conditional answers 
nor unconditional answers, the condition tnot(g)is true. 
This conclusion is propagated by simplifying the conditions for all 
answers that depend ontnot(g). This may result in a 
definite false condition, in which case the answer is removed 
or a definite true condition in which case the answer is made 
unconditional. Both events can make other conditional answers definitely 
true or false, etc.
- At the end of the simplifying process some answers may still be 
conditional. A final answer completion step analyses the graph 
of depending nodes, eliminating positive loops, e.g., “p 
:- q. q :- p” . The answers in 
such a loop are removed, possibly leading to more simplification. This 
process is executed until fixed point is reached, i.e., no 
further positive loops exist and no further simplification is possible.
The above process may complete without any remaining conditional 
answers, in which case we are back in the normal Prolog world. It is 
also possible that some answers remain conditional. The most obvious 
case is represented by undefined/0. 
The toplevel responds with
undefined instead of true if an answer is conditional.
- undefined
- Unknown represents neither truenorfalsein 
the well formed model. It is implemented as
:- table undefined/0.
undefined :- tnot(undefined). 
 
Solving a set of predicates under 
well formed semantics results in a
residual program. This program contains clauses for all tabled 
predicates with condition answers where each clause head represents and 
answer and each clause body its condition. The condition is a 
disjunction of conjunctions where each literal is either a tabled goal 
or tnot/1 
of a tabled goal. The remaining model has at least a cycle through a 
negative literal (tnot/1) 
and has no single solution in the stable model semantics, i.e., 
it either expresses a contradiction (as undefined/0, 
i.e., there is no stable model) or a multiple stable models as in the 
program below, where both
{p} and {q} are stable models.
:- table p/0, q/0.
p :- tnot(q).
q :- tnot(p).
Note that it is possible that some literals have the same truth value 
in all stable models but are still undefined under the stable 
model semantics.
The residual program is an explanation of why an answer is undefined. 
SWI-Prolog offers the following predicates to access the residual 
program.
- call_residual_program(:Goal, 
-Program)
- True when Goal is an answer according to the Well Founded 
Semantics. If Program is the empty list, Goal is 
unconditionally true. Otherwise this is a program as described by delays_residual_program/2.
- call_delays(:Goal, 
-Condition)
- True when Goal is an answer that is true when Condition can 
be satisfied. If Condition is true, Answer 
is unconditional. Otherwise it is a conjunction of goals, each of which 
is associated with a tabled predicate.
- delays_residual_program(:Condition, 
-Program)
- Program is a list of clauses that represents the connected program 
associated with Condition. Each clause head represents a 
conditional answer from a table and each corresponding clause body is 
the condition that must hold for this answer to be true. The body is a 
disjunction of conjunctions. Each leaf in this condition is either a 
term tnot(Goal)or a plain Goal. Each
Goal is associated with a tabled predicate. The program 
always contains at least one cycle that involves tnot/1.
The toplevel supports two modes for reporting that it is undefined 
whether the current answer is true. The mode is selected by the Prolog 
flag
toplevel_list_wfs_residual_program. 
If true, the toplevel uses call_delays/2 
and delays_residual_program/2 
to find the conditional answers used and the residual program 
associated with these answers. It then prints the residual program, 
followed by the answer and the conditional answers. For undefined/0, 
this results in the following output:
?- undefined.
% WFS residual program
    undefined :-
        tnot(undefined).
undefined.
If the toplevel_list_wfs_residual_program 
is false, any undefined answer is a conjunction with undefined/0. 
See the program and output below.
:- table p/0, q/0.
p :- tnot(q).
q :- tnot(p).
?- p.
% WFS residual program
    p :-
        tnot(q).
    q :-
        tnot(p).
p.
?- set_prolog_flag(toplevel_list_wfs_residual_program, false).
true.
?- p.
undefined.