I keep running across this operator. Here is an example, a predicate that uses insertion sort to sort a list of integers.
inser(A,[],[A],P).
inser(A,[H|L],R,P):- P(A,H),append([A,H],L,R),!.
inser(A,[H|L],[H|R],P):- inser(A,L,R,P).
sortin([],[],P).
sortin([H|L],Re,P):- sortin(L,R,P),inser(H,R,Re,P).
I am new to Prolog.
That's called cut. Citing from SWI-Prolog documentation page:
Cut. Discard all choice points created since entering the predicate in which the cut appears. In other words, commit to the clause in which the cut appears and discard choice points that have been created by goals to the left of the cut in the current clause
The name is descriptive WRT the abstract computation model of Prolog, that builds a proof tree attempting to satisfy all conditions in a well defined order. The cut prunes potential branchs that application of alternative rules could require.
In your inser/3 predicate, it means that the third clause will not be tried if P(A,H) succeeds and append([A,H],L,R) succeeds as well.
Note that P(A,H) is not valid Prolog syntax. You should use call(P,A,H) to invoke P comparison predicate.
Related
During my exploration of different ways to write down lists, I am intrigued by the following list [[a,b]|c] which appears in the book 'Prolog and Natural Language Analysis' by Pereira and Shieber (page 42 of the digital edition).
At first I thought that such a notation was syntactically incorrect, as it would have had to say [[a,b]|[c]], but after using write_canonical/1 Prolog returned '.'('.'(a,'.'(b,[])),c).
As far as I can see, this corresponds to the following tree structure (although it seems odd to me that structure would simply end with c, without the empty list at the end):
I cannot seem to find the corresponding notation using comma's and brackets though. I thought it would correspond to [[a,b],c] (but this obviously returns a different result with write_canonical/1).
Is there no corresponding notation for [[a,b]|c] or am I looking at it the wrong way?
As others have already indicated, the term [[a,b]|c] is not a list.
You can test this yourself, using the | syntax to write it down:
?- is_list([[a,b]|c]).
false.
You can see from write_canonical/1 that this term is identical to what you have drawn:
| ?- write_canonical([[a,b]|c]).
'.'('.'(a,'.'(b,[])),c)
In addition to what others have said, I am posting an additional answer because I want to explain how you can go about finding the reason of unexpected failures. When starting with Prolog, you will often ask yourself "Why does this query fail?"
One way to find explanations for such issues is to generalize the query, by using logical variables instead of concrete terms.
For example, in the above case, we could write:
?- is_list([[A,b]|c]).
false.
In this case, I have used the logical variable A instead of the atom a, thus significantly generalizing the query. Since the generalized query still fails, some constraint in the remaining part must be responsible for the unexpected failure. We this generalize it further to narrow down the cause. For example:
?- is_list([[A,B]|c]).
false.
Or even further:
?- is_list([[A,B|_]|c]).
false.
And even further:
?- is_list([_|c]).
false.
So here we have it: No term that has the general form '.'(_, c) is a list!
As you rightly observe, this is because such a term is not of the form [_|Ls] where Ls is a list.
NOTE: The declarative debugging approach I apply above works for the monotonic subset of Prolog. Actually, is_list/1 does not belong to that subset, because we have:
?- is_list(Ls).
false.
with the declarative reading "There is no spoon list." So, it turns out, it worked only by coincidence in the case above. However, we could define the intended declarative meaning of is_list/1 in a pure and monotonic way like this, by simply applying the inductive definition of lists:
list([]).
list([_|Ls]) :- list(Ls).
This definition only uses pure and monotonic building blocks and hence is monotonic. For example, the most general query now yields actual lists instead of failing (incorrectly):
?- list(Ls).
Ls = [] ;
Ls = [_6656] ;
Ls = [_6656, _6662] ;
Ls = [_6656, _6662, _6668] .
From pure relations, we expect that queries work in all directions!
I cannot seem to find the corresponding notation using comma's and brackets though.
There is no corresponding notation, since this is technically speaking not a real list.
Prolog has syntacical sugar for lists. A list in Prolog is, like a Lisp list, actually a linked list: every element is either an empty list [], or a node .(H,T) with H the head and T the tail. Lists are not "special" in Prolog in the sense that the intepreter handles them differently than any other term. Of course a lot of Prolog libraries do list processing, and use the convention defined above.
To make complex lists more convenient, syntactical sugar was invented. You can write a node .(H,T) like [H|T] as well. So that means that in your [[a,b]|c]. We have an outer list, which has one node .(H,c) and the ? is another list, with two nodes and an empty list H = .(a,.(b,[])).
Technically speaking I would not consider this a "real" list, since the tail of a list should have either another node ./2, or an empty list.
You can however use this with variables like: [[a,b]|C] in order to unify the tail C further. So here we have some sort of list with [a,b] as first element (so a list containing a list) and with an open tail C. If we later for instance ground C to C = [], then the list is [[a,b]].
I can't understand clearly the use of cut. For example in this case: flatten, is it really needed? It works for me even without both cut predicates (I tried removing). What are the cases that can cause the backtracking going to the cut?
Removing the cuts you have the same implementation of the book "The art of prolog" (Shapiro E.,Sterling L.) that is:
flatten([X|Xs],Ys) :-
flatten(X,Ysl),
flatten(Xs,Ys2),
append(Ys1,Ys2,Ys).
flatten(X,[X]) :-
constant(X),
X\=[].
flatten([],[]).
which leads me to another question: is it necessary in the second clause to check if it's not a list? If it's a single term won't unify with the first clause...isn't it?
The program linked in your question uses cut ! operator to prevent the code in the answer from unifying with other clauses. Without these cuts flatten2/2 from the answer would unify an empty list in the first argument with clauses one and three, i.e.
flatten2([], []) :- !.
flatten2(L, [L]).
Similarly, without a cut in the second clause flatten2/2 would unify a non-empty list in clauses two and three, leading to incorrect behavior.
Your code, on the other hand, has explicit checks to ensure that each clause of flatten/2 deals with one specific situation:
First clause recursively flattens non-empty lists
Second clause makes a single-item list from constants other than empty lists
Third clause "flattens" empty lists.
Since each clause applies exclusively to a single type of item on the left, the cut is not necessary. You could have rewritten your code with a cut by switching the second and the third clause, and adding a cut after matching an empty list, but I would strongly recommend against doing this (demo).
is it necessary in the second clause to check if it's not a list?
This check is necessary because an empty list [] is considered a constant, so your program would have incorrect behavior when empty lists are present in the list being flattened (demo).
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.
When I sort [(101,a),(42,b),(85,b)] is Prolog with sort([(101,a),(42,b),(85,b)],X). is get X = [ (42, b), (85, b), (101, a)]. But how come? Does Prolog recognize the tuples and sort them on the first element and then on the second element?
You should really simply look at the exact documentation of the Prolog you are using. In SWI-Prolog, for example, sorting is on "standard order". For compound terms (as you are using), it is first arity, then name, then recursively arguments. So in your case, yes, it is sorted first on first and then on second argument.
By the way, ISO sort should remove duplicates, not that you get surprised by it.
And strictly speaking, there are no "tuples" in Prolog. What you have there is the functor , with arity 2 (or, ,/2). Look at this:
2 ?- write_canonical((42, b)).
','(42,b)
true.
Your assumption seems reasonable. We can check some documentation, personally I like the documentation for ciao.
See page 235, then page 115. Notice you could also sort by keys.
You should be aware that some people consider using this kind of predicates (non-declarative) a bad practice. Basically there are two terms in this predicate, one must be grounded and the other one must not, so in fact this is a function and not a logical predicate. Those worried for the "purity" of logic programming would probably find a workaround not to use that.
My lecturer gave us this sample program to look at the code, while I understood the recursive function on a whole the was this one line I couldn't quite grasp the meaning of
all_different([H | T]) :- member(H, T), !, fail.
extracted from the recursive function:
all_different([H | T]) :- member(H, T), !, fail.
all_different([_ | T]) :- all_different(T).
all_different([_]).
all I understood about it is that it splits a list into a Head H and a Tail T and checks if H is contained in T...My question is, what is it that "!" and "fail" do?
These things are pretty fundamental to Prolog.
fail is essential. It forces Prolog to consider the current branch a failure and initiates backtracking.
The ! is called "the cut." It commits Prolog to the current branch. Or, it prunes the trail of choice points under the current rule.
Taken in conjunction, in Prolog-ese, this says "If the head of the list is present in the tail of the list, there is no need to look for any additional answers, and fail." Thus, if any element of the list is present in the remainder of the list, you'll get an immediate failure with no chance of backtracking. This isn't actually all that dire, it just means that Prolog won't waste any more time trying to figure out if the list is "all_different." Backtracking will resume at the call site normally.
It's important that these go in this order. If you tried to cut after the fail, you'd never make it to the cut, because backtracking would already have begun. If you omit the cut, the predicate will return true if there is any sublist of the list which satisfies the property. This is guaranteed to be the case for any non-empty list by the last clause, which asserts that a list with one element satisfies the property. If you omit the fail, you're just going to get one success for each element of the list that is in a sublist, plus one for the tail. I encourage you to try playing around with the predicate, making these changes and seeing the effects, because it will go a long way to illustrating the purpose of the cut and fail.