I want to write all of a list in prolog. But the problem is I don't want to use recursion.
So I want to to this iteratively.
Strictly speaking, there is no way how you can avoid recursion when you want to express some relation about all (or sufficiently many) elements in a list. However, you might delegate the recursive part to some library predicate.
Take the maplist-family as an example. Say maplist(=(_), Xs) which describes all lists whose elements are the same. To you, there is no longer any recursion. But behind, there is a recursive definition:
maplist(_C_1, []).
maplist(C_1, [E|Es]) :-
call(C_1, E),
maplist(C_1, Es).
There are also other ways to realize shortcuts for recursive predicates, like do-loops and B-Prolog's loops. But ultimately, they all translate to some recursive definition (or call recursive predicates).
There is really no reason to worry about using recursion in Prolog. After all, systems are quite optimized to handle recursion efficiently. Often, recursive predicates "run like" simple loops in imperative programming languages. Also, memory allocation is very well targeted to clean up intermediary/volatile data.
With Swi-Prolog, I have been experimenting with the fact that findall/3 unifies it's last list-argument, aka. it can "run on reverse" or input/output swapped, something like this findall(,,[a,b,c])
Then I came up with this:
Li=[a,b,c,d,e,f,g,h],findall(A, (append(A,B,Li),B=[C|_],writeln(C)), _).
A and B gets instantiated to sublists
Even this works!!
Li=[a,b,c,d,e,f,g,h],findall(_, (append(_,B,Li),B=[C|_],writeln(C)), _).
http://swish.swi-prolog.org/p/oMEAdQWk.pl
Well I don't know how efficient the code is, propably is not efficient. And you should first learn the recursive rules of Prolog :)
Related
When I was writing down this question on an empty list as a difference list I wanted to test what I knew about those structures. However, when I tried something as simple as comparing different notations it seemed that I was wrong and that I did not understand what is actually going on with difference lists.
?- L = [a,b,c|[d,e]]-[d,e], L = [a,b,c].
false % expected true
I tested this on SWI-Prolog as well as SICStus. I verified the notation as this is how it is written in Bratko's Prolog Programming for AI, page 210, but apparently unification is not possible. Why is that? Don't these notations have the same declarative meaning?
I think you have the idea that the Prolog interpreter treats difference lists as something special. That is not the case: Prolog is not aware of the concept of a difference list (nor of nearly every concept except some syntactical sugar). He only sees:
L=-( |(a, |(b, |(c, |(d, |(e, []))))), |(d, |(e, [] )))
where -/2 and |/2 are functors, and a, b, c, d, e and [] are constants.
Difference lists are simply a programming technique (like for instance dynamic programming is a technique as well, the compiler cannot detect nor treat dynamic programming programs differently). It is used to efficiently unify a (partially) ununified part deep in an expression.
Say you want to append/3 two lists. You can do this as follows:
%append(A,B,C).
append([],L,L).
append([H|T],L,[H|B]) :-
append(T,L,B).
But this runs in O(n): you first need to iterate through the entire first list. If that list contains thousands of elements, it will take a lot of time.
Now you can define yourself a contract that you will feed an append_diff/3 not only the list, but a tuple -(List,Tail) where List is a reference to the beginning of the list, and Tail is a reference to the end of the not unified list. Examples of structures that fulfill this requirement are Tail-Tail, [a|Tail]-Tail, [1,4,2,5|Tail]-Tail.
Now you can effectively append_diff/3 in O(1) with:
append_diff(H1-T1,T1-T2,H1-T2).
Why? Because you unify the ununified tail of the first list with the second list. Now the ununified tail of the second lists becomes the tail of the final list. So take for instance:
append_diff([a|T1]-T1,[1,4,2,5|T2]-T2,L).
If you call the predicate, as you see above, T1 will unify with [1,4,2,5|T2], so now the first list collapses to [a|[1,4,2,5|T2]] or shorter [a,1,4,2,5|T2], since we also have a reference to T2, we can "return" (in Prolog nothing is returned), [a,1,4,2,5|T2]-T2: a new difference list with an open tail T2. But this is only because you give - a special meaning yourself: for Prolog - is simply -, it is not minus, it does not calculate a difference, etc. Prolog does not attach semantics to functors. If you would have used + instead of -, that would not have made the slightest difference.
So to return back to your question: you simply state to Prolog that L = -([a,b,c,d,e],[d,e]) and later state that L = [a,b,c]. Now it is clear that those two expressions cannot be unified. So Prolog says false.
I am currently studying logic programming, and learn Prolog for that case.
We can have a Knowledge Base, which can lead us to some results, whereas Prolog will get in infinite loop, due to the way it expands the predicates.
Let assume we have the following logic program
p(X):- p(X).
p(X):- q(X).
q(X).
The query p(john) will get to an infinite loop because Prolog expands by default the first predicate that is unified. However, we can conclude that p(john) is true if we start expanding the second predicate.
So why doesn't Prolog expand all the matching predicates (implemented like threads/processes model with time slices), in order to conclude something if the KB can conclude something ?
In our case for example, two processes can be created, one expanded with p(X) and the other one with q(X). So when we later expand q(X), our program will conclude q(john).
Because Prolog's search algorithm for matching predicates is depth-first. So, in your example, once matching the first rule, it will match again the first rule, and will never explore the others.
This would not happen if the algorithm is breadth-first or iterative-deepening.
Usually is up to you to reorder the KB such that these situations never happen.
However, it is possible to encode breadth-first/iterative-deepening search in Prolog using a meta-interpreter that changes the search order. This is an extremely powerful technique that is not well known outside of the Prolog world. 'The Art of Prolog' describes this technique in detail.
You can find some examples of meta-interpreters here, here and here.
Edit: There seems to have been some understandable confusion by me using the terms 1st and 2nd implementation referring to them in the order they were listed, after I had mentioned that the 2nd one listed was the first I tried implementing, so I reworded the relevant paragraphs. Sorry for the confusion.
Some motivational background: I am building a constraint solver in SWI Prolog, and to greatly optimize space and time, I've built a reverse index into the main constraint data structures. Whenever a "variable" in my system (not a Prolog variable) is assigned a value, I want to make sure this assignment does not make any other constraints unsatisfiable. I have an index from variables to constraints to quickly select the constraints to check. As some point, this boils down to applying a try_check/2 predicate to a given left-hand-side (LHS) and to all the elements of a right-hand-side list (RHS_L) whose indexes appear in a list (IdxL). Here's my current implementation:
%% FORALL Implementation
try_check_filtered(LHS, IdxL, RHS_L) :-
forall((member(Idx, IdxL), nth0(Idx, RHS_L, RHS)),
try_check(LHS, RHS)).
I also have an earlier implementation which does the same thing, but takes an additional argument at the 2nd position to keep track of the current list index (the list of indexes is sorted in ascending order):
%% Tail-Recursive Implementation
%%try_check_filtered(+LHS, +Idx, +IdxL, +RHS_L)
try_check_filtered(_LHS, _Idx, [], _RHS_L) :- !. % Stop when index list is empty
try_check_filtered(LHS, Idx, [Idx|Ti], [H|T]) :- !, % If at next index -> check
try_check(LHS, H),
Inext is Idx+1,
try_check_filtered(LHS, Inext, Ti, T).
try_check_filtered(LHS, Idx, IdxL, [_H|T]) :- % If not at next index -> skip
Inext is Idx+1,
try_check_filtered(LHS, Inext, IdxL, T).
try_check_filtered(_LHS, _Idx, _IdxL, []). % Done when at the end of RHS_L
I have two questions:
Is there a better way to implement this that I can't think of?
I was surprised to find that the forall implementation performs better than the tail-recursive one. In my mind, the tail-recursive has a linear time dispatch (walks down the list once to "call" all the necessary try_check), whereas the forall implementation has quadratic dispatch (linear number of calls to member, each causing another linear call to nth0). (If you're curious about the performance improvement I saw, in an execution that takes ~44s, using the forall implementation over the tail-recursive on saves about 4s).
One thought I had was that the tail-recursion optimization was not applied to my tail-recursive implementation, forcing multiple copies of the lists onto stack frames, thus making it slower.
In order to (hopefully) enable the tail-recursion optimization for my tail-recursive implementation, I tried to make my try_check/2 predicate deterministic by adding a cut (!) right at the end of the rule. Is that enough? Does it matter that the try_check/2 rule has temporary side effects: it asserts some facts, which it retracts before finishing, thus leaving the collection of facts unchanged. The performance I reported above was with the cut in the try_check/2 predicate.
I hope I gave sufficient information to have a constructive discussion. Thank you in advance for the replies!
Edit: Here's the (high level) implementation of try_check. The entire code is 2600 lines, many of which (probably half) are indirectly used by this check, so it is not possible to post here.
%% try_check_eni(+E1:effect, +E2:effect)
try_check_eni(E1, E2) :-
push_trying,
check_no_try,
( is_non_interfering(E1, E2)
-> (clear_try, pop_trying)
; (clear_try, pop_trying, fail))
, !.
push_trying/0 and pop_trying/0 assert and retract a trying/0 predicate which slightly modifies how some of the other predicates operate, so that I wouldn't have to duplicate the code used by checking predicates for the try_check predicates. is_non_interfering/2 is non-deterministic. In trying mode, is_non_interfering marks instantiated variables as try/1 so that the instantiation can be retracted by clear_try/0 after the constraint is checked.
nth0/3 has linear costs. Thus, the combination with member/2 and forall/2 has quadratic costs. In fact the second code variant does not take any advantage of the fact that the list of indices is in ascending order, while the first one does.
Try not to over-optimize at this stage of development: first perform right, then (and only then) perform fast.
Focus on clean readable code, choose the proper data-structures, make the right library choices... If the circumstances demand it, you could then replace random read accesses in lists with, say, some compound structures plus arg/3.
Also, your code might profit from first-argument indexing. Be careful when using cut and/or assert/retract, both can easily drag down correctness and performance.
When programming in Prolog I often write predicates whose behavior should be semi-deterministic when called with all arguments instantiated (and whose behavior should be non-deterministic otherwise).
A concrete use case for this is my predicate walk/3, which implements graph walks. Since multiple paths can exist between two vertices, the instantiation (+,+) gives multiple choicepoints after true. These are, however, quite useless. Calling code must explicitly use once/1 for performance reasons.
%! walk(+Graph:ugraph, +StartVertex, +EndVertex) is semidet.
%! walk(+Graph:ugraph, -StartVertex, +EndVertex) is nondet.
%! walk(+Graph:ugraph, +StartVertex, -EndVertex) is nondet.
%! walk(+Graph:ugraph, -StartVertex, -EndVertex) is nondet.
Semi-determinism can be forced by the use of once/1 in the calling context, but I want to implement semi-determinism as a property of the predicate walk/3, and not as something that has to be treated specially every time it is called.
In addition to concerns over code aesthetics, the calling context need not always know whether its call to walk/3 is semi-deterministic or not. For example:
%! cycle(+Graph:ugraph, +Vertex) is semidet.
%! cycle(+Graph:ugraph, -Vertex) is nondet.
cycle(Graph, Vertex):-
walk(Graph, Vertex, Vertex).
I have come up with the following solution, which does produce the correct behavior.
walk_wrapper(Graph, Start, End):-
call_ground_as_semidet(walk(Graph, Start, End)).
:- meta_predicate(call_ground_as_semidet(0)).
call_ground_as_semidet(Goal):-
ground(Goal), !,
Goal, !.
call_ground_as_semidet(Goal):-
Goal.
However, this solution has deficiencies:
It's not generic enough, e.g. sometimes ground should be nonvar.
It is not stylistic, requiring an extra predicate wrapper every time it is used.
It may also be slightly inefficient.
My question is: are there other ways in which often-occurring patterns of (non-)determinism, like the one described here, can be generically/efficiently/stylistically programmed in Prolog?
You should experiment with double negation as failure. Yes a ground goal can only be true or false, so it should not leave any choice points. Lets assume we have an acyclic graph, to make matters simple:
If I use this code:
edge(a, b). edge(a, c).
edge(a, d). edge(b, c).
edge(c, d). edge(c, e).
edge(d, e).
path(X,X).
path(X,Y) :- edge(X,Z), path(Z,Y).
The Prolog system will now leave choice points for closed queries:
?- path(a, e).
true ;
true ;
true ;
true ;
true ;
false.
In my opinion the recommended approach, to eliminate these
choice points and nevertheless have a multi-moded predicate,
is to use so called meta-programming in Prolog.
meta-programming is also sometimes derogeratively called
non-logical programming, since it is based on non-logical
predicates such as ground/1, !/0 or (+)/1. But lets call
it meta-programming when declarativity is not impacted.
You could write a wrapper smart/1 as follows, doing the
same as your call_ground_as_semidet/1, but with a small nuance:
smart(G) :- ground(G), !, \+ \+ G.
smart(G) :- G.
The Prolog system will not anymore leave a choice point for closed queries:
?- smart(path(a,e)).
true.
The advantage of \+ \+ over once, is that the former does
not only leave no choice points, but also removes the trail. It
is sometimes called the garbage collection meta-predicate of Prolog.
Not an answer but too long for a comment. Keep in mind I am not sure I understand exactly, so I want to re-state your question first.
To take your graph example. You want to be able to ask the following questions using the same call of the same predicate.
Given a graph,
Question 1: is vertex B reachable from vertex A (somehow)? - yes or no
Question 2: which vertices are reachable from A? - enumerate by backtracking
Question 3: from which vertices is B reachable? - enumerate by backtracking
Question 4: which A and B exist for which B is reachable from A? - enumerate by backtracking
And I might be wrong here, but it seems that answering Question 1 and Question 2 might employ a different search strategy than answering Question 3?
More generally, you want to have a way of saying: if I have a yes-or-no question, succeed or fail. Otherwise, enumerate answers.
Here comes my trouble: what are you going to do with the two different types of answers? And what are the situations in which you don't know in advance which type of answer you need? (If you do know in advance, you can use once(goal), as you said yourself.)
PS:
There is obviously setof/3, which will fail if there are no answers, or collect all answers. Are there situations in which you want to know some of the answers but you don't want to collect all of them? Is this an efficiency concern because of the size and number of the answers?
Not an answer but an advice.
Maybe I missunderstood your question. I think you are trying to address performance issues by forcing a predicate to be non-deterministic. That question is pointless: if p(X) is non-deterministic (multiple solutions), then p(X),! is deterministic (first solution only).
You should not address performance issues by altering program logic or predicate reversibility. I suggest a different approach:
First, take advantage of prolog indexing. For example:
cycle(+Graph:ugraph, +Vertex)
is NOT the same (in terms of performance) as:
cycle(+Vertex, +Graph:ugraph)
You should find documentation on prolog indexing (and performance impact) on the Web.
Second, write multiple implementations for the same problem. Each one will optimize performance for a different case. Then, write a predicate that chooses the best implementation for each case.
Because Prolog uses chronological backtracking(from the Prolog Wikipedia page) even after an answer is found(in this example where there can only be one solution), would this justify Prolog as using eager evaluation?
mother_child(trude, sally).
father_child(tom, sally).
father_child(tom, erica).
father_child(mike, tom).
sibling(X, Y) :- parent_child(Z, X), parent_child(Z, Y).
parent_child(X, Y) :- father_child(X, Y).
parent_child(X, Y) :- mother_child(X, Y).
With the following output:
?- sibling(sally, erica).
true ;
false.
To summarize the discussion with #WillNess below, yes, Prolog is strict. However, Prolog's execution model and semantics are substantially different from the languages that are usually labelled strict or non-strict. For more about this, see below.
I'm not sure the question really applies to Prolog, because it doesn't really have the kind of implicit evaluation ordering that other languages have. Where this really comes into play in a language like Haskell, you might have an expression like:
f (g x) (h y)
In a strict language like ML, there is a defined evaluation order: g x will be evaluated, then h y, and f (g x) (h y) last. In a language like Haskell, g x and h y will only be evaluated as required ("non-strict" is more accurate than "lazy"). But in Prolog,
f(g(X), h(Y))
does not have the same meaning, because it isn't using a function notation. The query would be broken down into three parts, g(X, A), h(Y, B), and f(A,B,C), and those constituents can be placed in any order. The evaluation strategy is strict in the sense that what comes earlier in a sequence will be evaluated before what comes next, but it is non-strict in the sense that there is no requirement that variables be instantiated to ground terms before evaluation can proceed. Unification is perfectly content to complete without having given you values for every variable. I am bringing this up because you have to break down a complex, nested expression in another language into several expressions in Prolog.
Backtracking has nothing to do with it, as far as I can tell. I don't think backtracking to the nearest choice point and resuming from there precludes a non-strict evaluation method, it just happens that Prolog's is strict.
That Prolog pauses after giving each of the several correct answers to a problem has nothing to do with laziness; it is a part of its user interaction protocol. Each answer is calculated eagerly.
Sometimes there will be only one answer but Prolog doesn't know that in advance, so it waits for us to press ; to continue search, in hopes of finding another solution. Sometimes it is able to deduce it in advance and will just stop right away, but only sometimes.
update:
Prolog does no evaluation on its own. All terms are unevaluated, as if "quoted" in Lisp.
Prolog will unfold your predicate definitions as written and is perfectly happy to keep your data structures full of unevaluated uninstantiated holes, if so entailed by your predicate definitions.
Haskell does not need any values, a user does, when requesting an output.
Similarly, Prolog produces solutions one-by-one, as per the user requests.
Prolog can even be seen to be lazier than Haskell where all arithmetic is strict, i.e. immediate, whereas in Prolog you have to explicitly request the arithmetic evaluation, with is/2.
So perhaps the question is ill-posed. Prolog's operations model is just too different. There are no "results" nor "functions", for one; but viewed from another angle, everything is a result, and predicates are "multi"-functions.
As it stands, the question is not correct in what it states. Chronological backtracking does not mean that Prolog will necessarily backtrack "in an example where there can be only one solution".
Consider this:
foo(a, 1).
foo(b, 2).
foo(c, 3).
?- foo(b, X).
X = 2.
?- foo(X, 2).
X = b.
So this is an example that does have only one solution and Prolog recognizes that, and does not attempt to backtrack. There are cases in which you can implement a solution to a problem in a way that Prolog will not recognize that there is only one logical solution, but this is due to the implementation and is not inherent to Prolog's execution model.
You should read up on Prolog's execution model. From the Wikipedia article which you seem to cite, "Operationally, Prolog's execution strategy can be thought of as a generalization of function calls in other languages, one difference being that multiple clause heads can match a given call. In that case, [emphasis mine] the system creates a choice-point, unifies the goal with the clause head of the first alternative, and continues with the goals of that first alternative." Read Sterling and Shapiro's "The Art of Prolog" for a far more complete discussion of the subject.
from Wikipedia I got
In eager evaluation, an expression is evaluated as soon as it is bound to a variable.
Then I think there are 2 levels - at user level (our predicates) Prolog is not eager.
But it is at 'system' level, because variables are implemented as efficiently as possible.
Indeed, attributed variables are implemented to be lazy, and are rather 'orthogonal' to 'logic' Prolog variables.