Prolog argument mode indicator causes output false - syntax

I am trying to use Prolog's argument mode indicators in the signature of my method (https://www.swi-prolog.org/pldoc/man?section=argmode).
Without the indicators, my function works as expected (eg. palindrome([1,2,1]) gives true):
palindrome(List) :-
reverse(List, List)
But when I say
palindrome(+List) :-
reverse(List, List)
I get false every time. I don't get any errors or warnings. I also tried the following but had no luck:
palindrome(+List) :-
reverse(+List, +List)
So I'm pretty sure I am using these indicators wrong somehow. Can anyone help? I am using SWI-Prolog and the SWISH online IDE.

Yes, wrong. You shouldn't be using them at all, in the code. Only in the comments.
+ is interpreted as a separate token:
6 ?- atom(+X).
false.
7 ?- +X =.. Z.
Z = [+, X].
8 ?- +X = + X.
true.
9 ?- +X = '+'(X).
true.
You could use the +-using predicate definition as you show, but it's rather pointless:
14 ?- [user].
bar(+X,+X).
|:
true.
15 ?- bar( + 1, +Z).
Z = 1.
There are languages that do let us declare the modes, like I think Mercury does. But not Prolog. In Prolog we only use this as comments, to guide our use and understanding of the code.

Related

Different answers when using anonymous variable and "normal" variable in Prolog

I have the following database:
vegetarian(jose).
vegetarian(james).
vegetable(carrot).
vegetable(egg_plant).
likes(jose,X):-vegetable(X).
loves(Who,egg_plant):-vegetarian(Who).
When I do the query vegetarian(_). I was expecting to get _ = jose; _ = james. but I am instead getting true; true.
If I instead do vegetarian(X)., then I get the expected answer X = jose; X = james.
Why this difference?
If you're using SWI-Prolog, you can control this with the flag toplevel_print_anon). However, a name consisting of a single underscore (_) is special and never prints.
$ swipl dd.pl
Welcome to SWI-Prolog (threaded, 64 bits, version 8.3.16)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
Please run ?- license. for legal details.
For online help and background, visit https://www.swi-prolog.org
For built-in help, use ?- help(Topic). or ?- apropos(Word).
?- set_prolog_flag(toplevel_print_anon, true).
true.
?- vegetarian(_X).
_X = jose ;
_X = james.
?- vegetarian(_).
true ;
true.
?- set_prolog_flag(toplevel_print_anon, false).
true.
?- vegetarian(_X).
true ;
true.

Is it possible to write an inconsistent Prolog program using only pure Prolog, cut and `false`?

This one tickled my interest in theory:
Is it possible to write an inconsistent Prolog program, i.e. a program that answers both false and true depending on how it is queried, using only pure Prolog, the cut, and false?
For example, one could query p(1) and the Prolog Processor would says false. But when one queries p(X) the Prolog Processor would give the set of answers 1, 2, 3.
This can be easily achieved with "computational state examination predicates" like var/1 (really better called fresh/1) + el cut:
p(X) :- nonvar(X),!,member(X,[2,3]).
p(X) :- member(X,[1,2,3]).
Then
?- p(1).
false.
?- p(X).
X = 1 ;
X = 2 ;
X = 3.
"Ouch time" ensues if this is high-assurance software. Naturally, any imperative program has no problem going off the rails like this on every other line.
So. can be done without those "computational state examination predicates"?
P.S.
The above illustrates that all the predicates of Prolog are really carrying a threaded hidden argument of the "computational state":
p(X,StateIn,StateOut).
which can be used to explain the behavour of var/1 and friends. The Prolog program is then "pure" when it only calls predicates that neither consult not modify that State. Well, at least that seems to be a good way to look at what is going on. I think.
Here's a very simple one:
f(X,X) :- !, false.
f(0,1).
Then:
| ?- f(0,1).
yes
| ?- f(X,1).
no
| ?- f(0,Y).
no
So Prolog claims there are no solutions to the queries with variables, although f(0,1) is true and would be a solution to both.
Here is one attempt. The basic idea is that X is a variable iff it can be unified with both a and b. But of course we can't write this as X = a, X = b. So we need a "unifiable" test that succeeds without binding variables like =/2 does.
First, we need to define negation ourselves, since it's impure:
my_not(Goal) :-
call(Goal),
!,
false.
my_not(_Goal).
This is only acceptable if your notion of pure Prolog includes call/1. Let's say that it does :-)
Now we can check for unifiability by using =/2 and the "not not" pattern to preserve success while undoing bindings:
unifiable(X, Y) :-
my_not(my_not(X = Y)).
Now we have the tools to define var/nonvar checks:
my_var(X) :-
unifiable(X, a),
unifiable(X, b).
my_nonvar(X) :-
not(my_var(X)).
Let's check this:
?- my_var(X).
true.
?- my_var(1).
false.
?- my_var(a).
false.
?- my_var(f(X)).
false.
?- my_nonvar(X).
false.
?- my_nonvar(1).
true.
?- my_nonvar(a).
true.
?- my_nonvar(f(X)).
true.
The rest is just your definition:
p(X) :-
my_nonvar(X),
!,
member(X, [2, 3]).
p(X) :-
member(X, [1, 2, 3]).
Which gives:
?- p(X).
X = 1 ;
X = 2 ;
X = 3.
?- p(1).
false.
Edit: The use of call/1 is not essential, and it's interesting to write out the solution without it:
not_unifiable(X, Y) :-
X = Y,
!,
false.
not_unifiable(_X, _Y).
unifiable(X, Y) :-
not_unifiable(X, Y),
!,
false.
unifiable(_X, _Y).
Look at those second clauses of each of these predicates. They are the same! Reading these clauses declaratively, any two terms are not unifiable, but also any two terms are unifiable! Of course you cannot read these clauses declaratively because of the cut. But I find this especially striking as an illustration of how catastrophically impure the cut is.

Variables for predicates in metagol

The following program noMetagolR is given in:
http://www.doc.ic.ac.uk/~shm/Papers/metagol_gram.pdf page 33.
parse(S,G1,G2) :- parse(s(0),S,[],G1,G2).
parse(Q,X,X,G1,G2) :- abduce(acceptor(Q),G1,G2).
parse(Q,[C|X],Y,G1,G2) :- Skolem(P), abduce(delta1(Q,C,P),G1,G3), parse(P,X,Y,G3,G2).
abduce(X,G,G) :- member(X,G).
abduce(X,G,[X|G]) :- not(member(X,G)).
Skolem(s(0)). Skolem(s(1)). ...
An example query is :
parse([],[],G1), parse([0],G1,G2), parse([0,0],G2,G3), parse([1,1],G3,G4), parse([0,0,0],G4,G5), parse([0,1,1],G5,G6), parse([1,0,1],G6,G),not(parse([1],G,G)), not(parse([0,1],G,G)).
The answer substitutions should return a learnt grammar for parity.
The program is said to run in Yap. I normally use SWI-prolog. Either way,
what do I do to make them understand Skolem/1 ? Presumbly this means that Skolem is a variable? I thought maybe using =.. but this does not work.
Also how many Skolem/1 facts are needed?
in SWI-Prolog, you can place in your source the directive
:- set_prolog_flag(allow_variable_name_as_functor,true).
see current_prolog_flag/2
example on REPL:
1 ?- set_prolog_flag(allow_variable_name_as_functor,true).
true.
2 ?- assert(X(1)).
true.
3 ?- X(Y).
Y = 1.

Prolog: stop condition?

Here's a very trivial Prolog knowledge base:
spouse(bill,cheryl).
married(X,Y) :- spouse(X,Y).
married(X,Y) :- spouse(Y,X).
I ran the following queries. Note that sometimes the answer is the correct name (only), but other times the answer is the correct name and "false".
1 ?- married(bill,X).
X = cheryl ;
false.
2 ?- married(cheryl,X).
X = bill.
3 ?- married(X,bill).
X = cheryl.
4 ?- married(X,cheryl).
X = bill ;
false.
Can someone explain this seemingly inconsistent behavior? Thanks in advance.
The false response from Prolog means that Prolog had a choice point to go back to in an attempt to find further answers and it found no more. The order in which your predicates and facts are set up can impact whether it thinks it has more choices to explore.
In the given case:
spouse(bill,cheryl).
married(X,Y) :- spouse(X,Y).
married(X,Y) :- spouse(Y,X).
1 ?- married(bill,X).
X = cheryl ;
false.
2 ?- married(cheryl,X).
X = bill.
3 ?- married(X,bill).
X = cheryl.
4 ?- married(X,cheryl).
X = bill ;
false.
In the two false cases, the query married/2 is satisfied by the first of two married/2 clauses. Once satisified, Prolog realizes it has another choice to make (the second married/2 clause), and prompts for you to look for more. You press ;, then Prolog explores the second (and final) clause, finds no more solutions, and comes back false.
Swap the order of your married/2 clauses and see what happens:
spouse(bill,cheryl).
married(X,Y) :- spouse(Y,X).
married(X,Y) :- spouse(X,Y).
?- married(bill,X).
X = cheryl.
?- married(cheryl,X).
X = bill ;
false.
?- married(X,bill).
X = cheryl ;
false.
?- married(X,cheryl).
X = bill.
As expected, the results are reversed since we've changed which queries are satisfied by the first clause.
The false response can appear inconsistent to beginning Prolog programmers and "feel" like an error or warning, but it's actually a perfectly normal Prolog response. Prolog is quite consistent in its behavior of attempting to find solutions and, when no more choices exist, will return false. If Prolog has exhausted all the other choices before it finds the final solution, it displays the solution and doesn't return false (as in the case above in which the second clause is the only solution).
There is a temptation to try and "clean up" the false responses by using cuts. Although this can have the desired short-term result, it is risky since you are removing choice points from the predicate and as you add data and logic may eliminate solutions which you really want.
Thus, in the modified case:
spouse(bill,cheryl).
spouse(emma,nate).
married(X,Y) :- spouse(X,Y), !. % If we found the spouse, we're done, no more!
married(X,Y) :- spouse(Y,X).
?- married(bill,X).
X = cheryl.
?- married(cheryl,X).
X = bill.
?- married(X,bill).
X = cheryl.
?- married(X, cheryl).
X = bill.
Yay, life is good! But wait, what if we do this:
?- married(X,Y).
X = bill,
Y = cheryl.
?-
Are bill and cheryl the only married couple? No... it left out nate and emma. The cut eliminated the rest of the solutions.

How do return both a variable result and a true/false in Prolog?

It sounds silly, but lets say my predicate largest/2 returns the largest element in a list...the output should look like this:
?- largest([1,2,3,4,5], X).
X = 5.
false.
I implemented largest, and it works like above except it doesn't output "false". How do I make it so it also outputs this "false." value? This is for an annoying assignment I have to finish. :(
That extra false. or No just means that the person running the program asked to get all possible solutions for X, not just the first possible solution.
On most interactive Prolog interpreters, you check to see if there is another solution by pressing the semicolon (;) key.
sounds like impossible, as if predicate fails, no binding of free variables happens, see
?- A=5.
A = 5.
?- A=5,false.
false.
however
?- A=5;false.
A = 5 ;
false.
To achieve this you should make your predicate "largest" non-deterministic. But to me this seems pretty silly.
If this was part of an assignment, it probably means that your predicate should not yield a second (possibly different) result after backtracking. Backtracking occurs if the user wants the next solution, often by pressing ;. The interpreter often indicates that another solution is possible when it knows there are still paths not fully evaluated.
Suppose you had a predicate foo/1 as follows:
foo(1).
foo(Bar) :-
foo(Baz),
Bar is Baz + 1.
If you ask foo(Bar), the interpreter will respond with Bar = 1. After repeatedly pressing ;, the interpreter will come back with Bar = 2, Bar = 3 and so on.
In your example, finding the largest of a list, should be deterministic. Backtracking should not yield a different answer.
It's up to you to interpret the assignment to mean that you have to allow backtracking but have it fail, or that it would be all right to not even have it backtrack at all.
There is something to the previous answers by #aschepler, #Xonix, and #SQB.
In this answer, we use clpfd for expressing declarative integer arithmetics.
:- use_module(library(clpfd)).
We define largest/2 using the built-in predicate member/2, library meta-predicate maplist/2, and the finite-domain constraint (#>=)/2:
largest(Zs, X) :-
member(X, Zs), % X is a member of the list Zs
maplist(#>=(X), Zs). % all Z in Zs fulfill X #>= Z
Sample queries:
?- largest([1,2,3,4,5], X).
X = 5.
?- largest([1,2,3,4,5,4], X).
X = 5 ;
false.
?- largest([1,2,3,4,5,5], X).
X = 5 ;
X = 5.
?- largest([1,2,3,4,5,5,4], X).
X = 5 ;
X = 5 ;
false.
?- largest([A,B,C,D], X).
A = X, X#>=D, X#>=C, X#>=B ;
B = X, X#>=A, X#>=D, X#>=C ;
C = X, X#>=A, X#>=D, X#>=B ;
D = X, X#>=A, X#>=C, X#>=B.

Resources