Sorting program for SWI Prolog - prolog

Why this program answers False in SWI-PROLOG?
sor(x, y):- sorted(y), perm(x, y).
sorted([]).
sorted([x, []]).
sorted([x, y, z]):- mi(x, y), sorted([y, z]).
perm([], []).
perm([x,y],[u,v]):- delete(u,[x,u],z), perm(z,v).
delete(x,[x,y],y].
delete(x, [y, z], [y, w]):- delete(x,z,w).
mi(0, x).
mi(s(x), s(y)):- mi(x, y).
for the query ?-
sor([s(s(s(s(s(0))))), s(s(s(s(s(s(0)))))), s(s(s(0))), s(s(0)), []], y).
This is an adaptation to SWIProlog of an inefficient sorting-program used as example in the book Foundations of Logic Programming, by Loyd (you can find the original SLOWSORT program example in this pdf, on page 9)
SWI Prolog is a standard Prolog, isn't it?
Edit
Now I have tried to correct the program (looking a little to the lists syntax in Prolog)
sor(X, Y):- perm(X, Y), sorted(Y).
sorted([]).
sorted([X|[]]).
sorted([X|[Y|Z]]):- mi(X, Y), sorted([Y|Z]).
perm([], []).
perm([X|Y],[U|V]):- delete(U,[X|Y],Z), perm(Z, V).
delete(X,[X|Y],Y).
delete(X, [Y|Z], [Y|W]):- delete(X, Z, W).
mi(0, X).
mi(s(X), s(Y)):- mi(X, Y).
and changing the query in
sor([s(s(s(s(s(0)))))|[ s(s(s(s(s(s(0))))))|[s(s(s(0)))|[ s(s(0))|[]]]]], Y).
Well, Prolog now gives success, but it gives this substitution
Y = [s(s(0)), s(s(s(0))), s(s(s(s(s(0))))), s(s(s(s(s(s(...))))))]
and I don't understand the meaning of (...): Why not (0)?
Edit2
I notice that after giving the command swipl -s slowsort.pl I obtain this error message
Warning: /home/navigazione/Scrivania/slowsort.pl:3:
Singleton variables: [X]
Warning: /home/navigazione/Scrivania/slowsort.pl:9:
Singleton variables: [X]
It seems to refer to 3th and 9th rows of the program, but I don't understand what it means.

Great, you managed to translate it to correct Prolog :)
What you see is the top level trying to make things readable by omitting stuff (the ... means there is stuff there that is not shown). See this question and answers for different ways you can tell the top level to show the complete term instead of hiding parts of it.
As for the singleton variable warnings, it just tells you that you have logical variables (on lines 3 and 9) that you have only mentioned once in their syntactical scope. You can write _X instead of X to make it explicit that you are not using the value of the variable in that scope.

Related

Should I enforce mode declarations by throwing instantiation errors?

I have been working on some code in which I have predicates that either do not terminate or give incorrect solutions if they are used in certain modes.
Here is an example:
%! list_without_duplicates(+List1, -List2) is det.
%
% True if List2 contains all the elements of List1 but has
% no duplicate elements.
%
% Ex: list_without_duplicates([1,1,2,2,3,3],[1,2,3]).
list_without_duplicates([],[]).
list_without_duplicates([X|Xs],[X|Acc]) :-
\+ memberchk(X,Xs),
list_without_duplicates(Xs,Acc).
list_without_duplicates([X|Xs],Acc) :-
memberchk(X,Xs),
list_without_duplicates(Xs,Acc).
% This is great.
?- list_without_duplicates([1,1,2,2,3,3],X).
X = [1, 2, 3] ;
false.
% This is not great.
list_without_duplicates_(X,[1,2,3]).
ERROR: Stack limit (1.0Gb) exceeded
ERROR: Stack sizes: local: 1Kb, global: 0.8Gb, trail: 0.1Mb
ERROR: Stack depth: 16,586, last-call: 100%, Choice points: 5
...
So my question is, am I better off throwing an error if the first argument is not instantiated?
list_without_duplicates(List1,List2) :-
( var(List1)
-> instantiation_error(List1)
; list_without_duplicates_star(List1,List2)
).
list_without_duplicates_star([],[]).
list_without_duplicates_star([X|Xs],[X|Acc]) :-
\+ memberchk(X,Xs),
list_without_duplicates_star(Xs,Acc).
list_without_duplicates_star([X|Xs],Acc) :-
memberchk(X,Xs),
list_without_duplicates_star(Xs,Acc).
I have been reading through some Prolog libraries such as apply.pl, which on my system is located in /usr/local/logic/lib/swipl/library/apply.pl. Here is code directly from this library. Note that no instantiation errors are mentioned anywhere here.
maplist(Goal, List1, List2) :-
maplist_(List1, List2, Goal).
maplist_([], [], _).
maplist_([Elem1|Tail1], [Elem2|Tail2], Goal) :-
call(Goal, Elem1, Elem2),
maplist_(Tail1, Tail2, Goal).
Yet if I use this predicate like so I get an instantiation error:
?- use_module(library(apply)).
true.
?- apply:maplist(X,[1,2,3],[4,5,6]).
ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR: [11] apply:maplist_([1,2|...],[4,5|...],apply:_5706)
ERROR: [9] toplevel_call(user:apply: ...) at /usr/local/logic/lib/swipl/boot/toplevel.pl:1113
ERROR:
ERROR: Note: some frames are missing due to last-call optimization.
ERROR: Re-run your program in debug mode (:- debug.) to get more detail.
I do not understand how Prolog knows to throw this error.
am I better off throwing an error if the first argument is not instantiated?
In your case not much. In fact, the non-termination you encountered was annoying and resource-wasting but at least not incorrect. I would be more concerned about cases like:
?- Y = b, list_without_duplicates([a,Y],[a,b]).
Y = b
; false. % inefficiency
?- list_without_duplicates([a,Y],[a,b]).
false. % incompleteness
It gets even worse in the presence of constraints.
As a general rule-of-thumb, whenever you want to discern according to instantiations, test for the more instantiated pattern. In your case, do not test with var/1, instead rather use nonvar/1. This focuses your attention on the safer case. And in your case you might have realized that nonvar/1 alone is not enough. In fact, use ground/1:
list_without_duplicates(List1,List2) :-
( ground(List1)
-> list_without_duplicates_star(List1,List2)
; instantiation_error(List1)
).
Consider using iwhen/2 to hide the details; and get an easy upgrade to coroutining: just delete the i and you are using when/2.
In general, instantiation errors are here to mask out procedural problems. Some of them are related to non-termination, and others help to mask-out the non-relational parts of impure code like memberchk/2.
The question then remains, why write impure code in the first place? Even more so if it is quite inefficient as yours? With library(reif) you get a clean, pure and quite efficient solution:
:- use_module(library(reif)).
list_nub([], []).
list_nub([X|Xs], Ys0) :-
if_(memberd_t(X,Xs), Ys0 = Ys1, Ys0 = [X|Ys1]),
list_nub(Xs, Ys1).
Answering #gusbro's remark on performance in SWI, here is the expansion in SICStus Prolog (to get that listing, I declared list_nub/2 dynamic). The expansion should look similar in SWI.
list_nub([], []).
list_nub([A|B], C) :-
memberd_t(A, B, D),
( D==true ->
C=E
; D==false ->
C=[A|E]
; nonvar(D) ->
throw(error(type_error(boolean,D),type_error(call(user:memberd_t(A,B),D),2,boolean,D)))
; throw(error(instantiation_error,instantiation_error(call(user:memberd_t(A,B),D),2)))
),
list_nub(B, E).
I would refrain from directly throwing in your Prolog code unless you are absolutely certain you have no other choice.
Use the built-ins, they provide a lot of "type-checking" for free. Using call with a non-callable is one example. Basically all built-ins check their arguments and if they don't, I would consider this a bug and report it. Examples:
?- between(1, 3, foo).
?- succ(X, 0).
?- X = [_|X], length(X, N).
?- X is 3 - a.
?- X is 3 - A.
?- sort([a,b|c], Sorted).
To rephrase, as long as you find the appropriate built-in to use in your own code, you shouldn't need to throw explicitly.
If you are checking the arguments, go ahead and use library(error).
The "without duplicates" predicate is a perennial classic. You need a very good reason to not use sort/2 for this. If you did use sort/2, you will immediately get an error:
?- sort(X, Y).
ERROR: Arguments are not sufficiently instantiated
If you decide to program it yourself, you might as well go down the rabbit hole and use if_/3 as suggested by #false. As a matter of fact, you might find a fancy solution here on SO if you simply look through the links in the profile of #false.

Prolog existence error exception

Firstly, I'm not a prolog programmer. I'm doing an assignment for school where we build a small expert system. I've chosen to use prolog for the assignment and I'm following this book: http://www.amzi.com/distribution/files/xsip_book.pdf. Specifically I'm looking at chapter 2.
There is a procedure in this book that I would like to use called "ask." It can be found on page 14. Ask, uses another procedure called "known" to remember the answers to questions. I have basically copied this procedure for use in my code, but I am getting an existence error related to the "known" procedure. Not being a prolog programmer, I don't know how to debug it. Hopefully someone can help.
Here is a sample run of my code:
| ?- species(X).
uncaught exception: error(existence_error(procedure,known/3),ask/2)
Here is the code:
species(limba) :- %There are a bunch of these
distribution(west_africa),
color(tan_with_black_streaks),
figure(plain),
janka_hardness(670),
workability(easy).
distribution(X) :- ask(distribution, X).
color(X) :- ask(color, X).
figure(X) :- ask(figure, X).
janka_hardness(X) :- ask(janka_hardness, X).
workability(X) :- ask(workability, X).
ask(A, V) :-
known(yes, A, V),
!.
ask(A, V) :-
known(_, A, V),
!,
fail.
ask(A, V) :-
write(A:V),
write('? : '),
read(Y),
asserta(known(Y, A, V)),
Y == yes.
This program expects known/3 to be dynamic (and the book you pointed to says this). That is, it's created and managed at run time. The Prolog documentation tells you how to declare a dynamic predicate. You might want to read through it. – lurker

No termination of predicate

I have some program about a graph with black and white vertices:
black(root).
black(v1).
black(v3).
black(v4).
edge(root,root).
edge(v1,root).
edge(v2,v1).
edge(v3,v1).
edge(v4,v3).
edge(v5,v2).
edge(v5,v4).
edge(v6,v5).
vertex(X) :- edge(X,_).
vertex(X) :- edge(_,X).
white(X) :-
vertex(X),
not(black(X)).
foo(root).
foo(X) :-
edge(X,Y),
black(Y),
foo(Y).
when I run the goal foo(X) I get a problem:
If I remove the fact edge(root,root) the program find some solutions (6 different solutions). Otherwise, I get infinite solutions and all are X=root.
Why does this happen?
First a quick answer which shows you a bit how a Prolog programmer looks at your program, the explanation to it is below. Your program does not terminate, because the following failure-slice does not terminate:
black(root).
black(v1) :- false.
black(v3) :- false.
black(v4) :- false.
edge(root,root).
edge(v1,root) :- false.
edge(v2,v1) :- false.
edge(v3,v1) :- false.
edge(v4,v3) :- false.
edge(v5,v2) :- false.
edge(v5,v4) :- false.
edge(v6,v5) :- false.
foo(root) :- false.
foo(X) :- X = root, Y = root,
edge(X,Y),
black(Y),
foo(Y), false.
All through-striken text is irrelevant to understand non-termination. As you can see the remainder is relatively short and thus fast to grasp.
Prolog is not able to detect this loop directly. However, you can use closure0/3 defined here for this purpose:
edge_toblack(X, Y) :-
edge(X, Y),
black(Y).
foo(X) :-
closure0(edge_toblack, X,root).
Now for the details.
Before answering your question why this happens, let's take a step back. We need first to find a good way to observe the problem. The goal foo(X) does produce answers, actually only X = root. So maybe you are just impatient waiting Prolog to finish? By asking the query foo(X), false instead, we get rid of these irritating, eye-straining answers, and we will just wait to get false as an answer back.
Still we cannot be sure about the non-termination property of the program. But we can narrow down the actual reason by inserting goals false (and also (=)/2). In the above failure-slice I have inserted the maximum. If you are just starting, simply add one false and then reload the program and retry the query. With some experience you will soon be able to identify such parts rapidly. So now we only have to understand
foo(root) :-
edge(root,root), % always true
black(root), % always true
foo(root), false.
or even shorter
foo(root) :-
foo(root).
Prolog's very simple but efficient execution mechanism does not detect such loops. There are essentially several ways out:
add loop detection manually. This is typically very prone to errors
use closure0/3 - see above
write your own meta-interpreter to detect loops in general
use a language extension like tabling, offered in B-Prolog or XSB-Prolog.

Why does Prolog crash in this simple example?

likes(tom,jerry).
likes(mary,john).
likes(mary,mary).
likes(tom,mouse).
likes(jerry,jerry).
likes(jerry,cheese).
likes(mary,fruit).
likes(john,book).
likes(mary,book).
likes(tom,john).
likes(john,X):-likes(X,john), X\=john.
Hi there, above is a very simple prolog file, with some facts and only one rule: John likes anyone who likes him.
But after loading this file and ask Prolog the following query:
likes(john,X).
The program crashes. The reason is somehow prolog gets stuck at likes(john,john) even though the rule states that X\=john.
Any advice?
Ironically, given the site we're on, you're getting a stack overflow.
It does this because of the order of execution that prolog uses, it's going to go into an infinite recursion at likes(X,john) in your rule, it activates the rule again - not a fact - never getting to the X\=john bit.
One way to fix this is to have your rule named differently from your fact like this:
kindoflikes(tom,jerry).
kindoflikes(mary,john).
kindoflikes(mary,mary).
kindoflikes(tom,mouse).
kindoflikes(jerry,jerry).
kindoflikes(jerry,cheese).
kindoflikes(mary,fruit).
kindoflikes(john,book).
kindoflikes(mary,book).
kindoflikes(tom,john).
likes(Y,X):- kindoflikes(X,Y), X\=Y.
likex(Y,X):- kindoflikes(Y,X), X\=Y.
Note the reversal of X and Y in the kindoflikes in the two rule definitions.
So you get:
?- likes(john,X).
X = mary ;
X = tom ;
X = book.
But you're not locked into finding what john likes, and you can do:
?- likes(jerry,X).
X = tom ;
X = cheese.
Your first question was why your program crashes. I am not sure what kind of Prolog system you are using, but many systems produce a clean "resource error" which can be handled from within Prolog.
Your actual problem is that your program does not terminate for the query likes(john, X). It gives you the expected answers and only then it loops.
?- likes(john,X).
X = book
; X = mary
; X = tom
; resource_error(local_stack). % ERROR: Out of local stack
You have been pretty lucky that you detected that problem so rapidly. Imagine more answers, and it would have not been that evident that you have the patience to go through all answers. But there is a shortcut for that. Ask instead:
?- likes(john, X), false.
This false goal is never true. So it readily prevents any answer. At best, a query with false at the end terminates. Currently this is not the case. The reason for this non-termination is best seen when considering the following failure-slice (look up other answers for more details):
?- likes(john,X), false.
loops.
likes(tom,jerry) :- false.
likes(mary,john) :- false.
likes(mary,mary) :- false.
likes(tom,mouse) :- false.
likes(jerry,jerry) :- false.
likes(jerry,cheese) :- false.
likes(mary,fruit) :- false.
likes(john,book) :- false.
likes(mary,book) :- false.
likes(tom,john) :- false.
likes(john,X) :-
likes(X,john), false,
X\=john.
So it is this tiny little part of your program that is responsible for the stack overflow. To fix the problem we have to do something in that tiny little part. Here is one: add a goal dif(X, john) such that the rule now reads:
likes(john,X) :-
dif(X, john),
likes(X,john).
dif/2 is available in many Prolog systems like: SICStus, SWI, YAP, B, IF.

Problem with `\+` in Prolog queries with variables

I'm reading "Seven languages in seven weeks" atm, and I'm stumped over some Prolog query that I don't understand the 'no' response to.
The friends.pl file looks like this:
likes(wallace, cheese).
likes(grommit, cheese).
likes(wendolene, sheep).
friend(X, Y) :- \+(X = Y), likes(X, Z), likes(Y, Z).
I can do some trivial queries on it, such as:
| ?- ['friends'].
compiling /home/marc/btlang-code/code/prolog/friends.pl for byte code...
/home/marc/btlang-code/code/prolog/friends.pl compiled, 12 lines read - 994 bytes written, 8 ms
yes
| ?- friend(wallace,grommit).
yes
| ?- friend(wallace,wendolene).
no
This is all as expected. Now, I want to introduce a variable in the query. My intent being that Prolog will give me a list of all of Wallace's friends. I'm expecting X = grommit, but I'm getting no:
| ?- trace.
The debugger will first creep -- showing everything (trace)
yes
{trace}
| ?- friend(wallace,X).
1 1 Call: friend(wallace,_16) ?
2 2 Call: \+wallace=_16 ?
3 3 Call: wallace=_16 ?
3 3 Exit: wallace=wallace ?
2 2 Fail: \+wallace=_16 ?
1 1 Fail: friend(wallace,_16) ?
no
{trace}
It doesn't even try to unify X (_16) with grommit. Why?
It is the definition of friend:
friend(X, Y) :- \+(X = Y), likes(X, Z), likes(Y, Z).
The important thing here is that you start with \+(X = Y) which is normally defined as:
\+ Goal :- Goal,!,fail
Note that this means that if goal succeeds, you are sure to fail. Free variables (ones that havent been assigned) will always unify, and thus be equal, so you will always fail with a free variable. It will thus never assign a value to X or Y if it doesn't already have one.
Instead
friend(X, Y) :- likes(X, Z), likes(Y, Z), \+(X = Y)
will behave more as you expect.
The problem here is that prolog gives you powerful ways to control the flow of programs, but those dont really fit nicely with its more logic oriented design. It should be possible to express "negation as failure" type constraints in a way that does not produce these problems. I'm not a huge prolog fan for this reason.
Regarding Philip JF's comment above:
It should be possible to express
"negation as failure" type constraints
in a way that does not produce these
problems.
This is possible: The modern solution for such problems are constraints. In this case, use for example dif/2, available in all serious Prolog systems.
The first subgoal of friend/2 is \+(X = Y). This is executed by first trying to find a solution for X = Y, then negating that result. The predicate =/2 is roughly the equivalent of unify/2, that is it tries to unify the left operand with the right operand. Now, when you are asking queries using e.g. friend(wallace, gromit), the two atoms wallace and gromit do not unify; but when a free variable is thrown into the mix, it always unifies with whatever term is given, so X = Y is always successful, therefore \+(X = Y) always fails, and the execution never gets past that first subgoal.
Another issue with having the inequality constraint first is: It is uncapable to find a binding for the unbound X (excluding the trivial case of unifying it with grommit for the moment). Prolog finds bindings by running through its database, trying to unify the unbound variable. That is why likes(grommit, Z) will find some binding for Z which can then be further processed, because there are likes clauses in the database. But there are no such clauses for the inequality of grommit with something, so Prolog cannot produce any bindings. As things stand, the friend predicate has to make sure that all variables are bound before the inequality can be tested.

Resources