Predicate retruns false when callled from other predicate - prolog

I have this program in Prolog
su([], Counter, Counter).
su([G|O], N, Count) :- Counter is Count + G, su(O,N,Counter).
custom_sum(L,X) :- su(L,X,0).
write_file :-
write('Type list: '),
read(L1),
tell('file.txt'),
write(L1), write(.), nl,
told.
read_file :-
write('Reading from file...'), nl,
see('file.txt'),
read(L),
seen,
write('sum of list elements: '),
custom_sum(L,Sum),
write(Sum), assertz(my_sum(Sum)).
When I try to use custom_sum, everything is fine. Same with write_file. But read_file returns false right after "write('sum of list elements: ')". As if custom_sum was a problem here.

Out of curiosity I ran your code without changing anything. Your code works as I would expect on my system with SWI-Prolog on Windows 10.
Welcome to SWI-Prolog (threaded, 64 bits, version 8.1.24)
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).
?- consult("C:/Users/Groot/Documents/Projects/Prolog/SO_question_180.pl").
true.
?- custom_sum([1,2,3],R).
R = 6.
?- working_directory(Working_directory,'C:/Users/Groot/Documents/Projects/Prolog/SO_question_180/').
Working_directory = 'c:/users/groot/documents/prolog/'.
?- working_directory(D,D).
D = 'c:/users/groot/documents/projects/prolog/so_question_180/'.
?- write_file.
Type list: [1,2,3].
true.
?- read_file.
Reading from file...
sum of list elements: 6
true.
?-
My only guess is that you are entering the list incorrectly at the prompt.
It should be [1,2,3]. You need the [ ] and the ending period . .
Contents of created file.txt
[1,2,3].

Related

Prolog argument mode indicator causes output false

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.

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.

Prolog predicate where two items are associated but not equivalent

I haven't programmed in Prolog for years and am struggling with a simple block of test code (I'm trying to solve a logic puzzle for fun...):
aboard(jack, blackbird).
aboard(jim, blackbird).
aboard(donna, blackbird).
aboard(david, north_star).
aboard(sandy, north_star).
shipmates(A, B) :- A \= B, aboard(A, X), aboard(B, X).
shipmates1(A, A) :- !, fail.
shipmates1(A, B) :- aboard(A, X), aboard(B, X).
The shipmates and shipmates1 rules are two different attempts to accomplish the following: I want to pair all passengers who are on the same ship but are not equivalent to each other.
For example, I want shipmates(jack, jack). to be false.
When I query this with fully-qualified arguments, I get the expected answers:
3 ?- shipmates(jack, david).
false.
4 ?- shipmates(jack, jack).
false.
5 ?- shipmates(jack, jim).
true.
However, when I want all of Donna's shipmates, it doesn't seem to work:
6 ?- shipmates(donna, X).
false.
I was expecting:
X = jack ;
X = jim ;
NOTE: I get the same wrong results with shipmates1.
So please take pity on a very amateur Prolog programmer (who is not doing homework for a class!) What very obvious thing am I doing wrong?
Version: SWI-Prolog (threaded, 64 bits, version 8.0.2)
Try:
shipmates(A, B) :-
aboard(A, X),
aboard(B, X),
A \= B.
By calling the aboard/2 predicate before the A \= B goal, you ensure that both A and B will be instantiated, thus making the comparison meaningful.

Need help Converting to Prolog rule

Everybody likes a job if it's fun and it pays
we=>likes(X, Job):-fun(Job), pay_well(Job).
Not sure if it's correct and if it matters that I put Job as a variable?
Just provide definitions for the other two predicates and you have a working program. Something along these lines:
likes_job(_Person, Job) :-
is_fun(Job),
pays_well(Job).
is_fun('scuba diving instructor').
is_fun('tour guide').
pays_well('software developer').
pays_well('scuba diving instructor').
A couple of examples:
?- likes_job('Peter', Job).
Job = 'scuba diving instructor' ;
false.
?- likes_job('Peter', 'software developer').
false.
?- likes_job('Peter', 'tour guide').
false.
?- likes_job('John', 'scuba diving instructor').
true.
?- likes_job(X, 'scuba diving instructor').
true.
Instead of defining the two predicates, you can just declare them as "dynamic" and they are now empty (instead of absent):
likes_job(_Person, Job) :-
is_fun(Job),
pays_well(Job).
:- dynamic is_fun/1.
:- dynamic pays_well/1.
$ swipl -q
?- [likesjob].
true.
?- likes_job(A, B).
false.
?- assertz(is_fun(x)).
true.
?- assertz(pays_well(x)).
true.
?- likes_job(A, B).
B = x.

Prolog -- better way to eliminate duplicate answer in special case?

I was having trouble with these two lines:
list_swizzle(L, [], L).
list_swizzle([], L, L).
The problem was that if the both of the first two arguments are the empty list, the first two statements would both be used, returning the same answer. However, if I put a cut in one, it wrecks backtracking. I eventually put in this line above them:
list_swizzle([], [], []):- !.
And it works. But I was wondering if there is a more elegant solution.
Here's my version:
list_swizzle([H|T], [], [H|T]).
list_swizzle([], L, L).
I'm counting on [] not unifying against [H|T] in the first fact. In other words [] has no T because it's the empty list so the first fact doesn't match goals with a [] in the first arg.
I've run this successfully on SWI-Prolog (Multi-threaded, 32 bits, Version 5.8.2)
$ cat tt.pl
s([H|T], [], [H|T]).
s([], L, L).
....
For help, use ?- help(Topic). or ?- apropos(Word).
?- [tt].
% tt compiled 0.00 sec, 920 bytes
true.
?- s(L,[],[]).
L = [].
?-
% halt

Resources