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
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.
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.
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.
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.
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