The problem with floundering is the fact that negation as failure is guaranteed to be sound only in presence of completely ground arguments. If a non-ground negative literal is selected during execution, the computation is not guaranteed to produce correct results.
The typical solution to the problem is to try to avoid floundering by delaying non-ground negative literals. This way floundering will occur only if the goal is composed exclusively by non-ground negative literals.
The following meta-interpreter sketches a solution to the problem (some details omitted):
%% Entry point of meta-interpreter solve(Goal) :- solve(Goal,[]). %% maintain a list of suspended goals %% Meta-interpreter with Suspension list solve(true,L) :- resume(L). %% resume suspended goals solve((A,B),L) :- A = not(G), !, (ground(G) -> solve_not(G), %% solve negation solve(B,L); solve(B,[A|L]) %% suspend negative literal ). solve((A,B),L) :- solve(A,X), append(X,L,New), solve(B,New). solve(not(G),L) :- !, (ground(G) -> solve_not(G), resume(L); resume([not(G)|L]) ). solve(A,L) :- clause(A,B), solve(B,L). %% Solving a negative ground goal solve_not(G) :- solve(G), !, fail. solve_not(_). %% Attempt to resume suspended goals resume([]). resume(L) :- L \== [], extract_ground(L,G,NG), (G == [] -> !,fail; solve(G,NG)). extract_ground([],[],[]). extract_ground([A|B],[A|G],NG) :- ground(A), !, extract_ground(B,G,NG). extract_ground([A|B],G,[A|NG]) :- extract_ground(B,G,NG).