I am using a higher order Prolog variant that lacks findall.
There is another question on implementing our own findall here: Getting list of solutions in Prolog.
The inefficient implementation is:
parent(pam, bob). %pam is a parent of bob
parent(george, bob). %george is a parent of bob
list_parents(A, Es, [X|Xs]) :-
parent(X, A),
\+ member(X, Es),
list_parents(A, [X|Es], Xs).
list_parents(A, Es, []).
The efficient one
need a "solutions" higher-order predicate:
list_parents(X, Ys) :- solutions(parent, [X, W], 1, Ys)
What is solutions? Can I implement my own solutions predicate in higher order lambda Prolog?
Yes, if
findall/3were not available, you could implement it for example via the dynamic database.For example, for the concrete use case of parents:
list_parents(_) :- parent(P, _), assertz(parent(P)), false. list_parents(Ps) :- phrase(retract_parents, Ps). retract_parents --> ( { retract(parent(P)) } -> [P], retract_parents ; [] ).Sample query:
You can combine this with
sort/2for asymptotically optimal performance, avoiding the quadratic overhead of the "naive" solution to remove duplicates.Beware though: First, this is not thread-safe. To make it thread-safe you need to add more information pertaining to the current thread.
Second, if you implement full-fledged
findall/3in this way, you must take care of nestedfindall/3calls.One way to do this is to assert two kinds of terms:
solution(S), such assolution(parent(pam)), indicating a concrete solution that was found on backtracking via the most recentfindall/3callmark, indicating that a newfindall/3starts hereWhen collecting solutions, you only proceed to the most recent
mark.See Richard O'Keefe's book for a good introduction to these issues.