Reputation: 69
I want to create a predicate, which recognizes a word (in this case: "save") and starts saving the next words, until the sign/word "end" comes.
It should work like this:
?- save.
one
two
end
true.
The predicate for saving:
save(X) :- assert(listitem(X)).
and then I started like this:
save :- read(save).
read:- X -> save(X).
end --> 'end'.
The problem is, that I can add as much words as I want, but if I want to stop the command with "end", the program fails and actually the words have not been saved.
What part of the predicate is wrong? I'd be very happy for some help. Thank you in advance!
Upvotes: 2
Views: 394
Reputation: 60014
I would use a 'state machine' approach: it's so simple!
:- dynamic listitem/1.
loop(Mode) :- read(W), loop(Mode, W).
loop(_, stop).
loop(skip, save) :- loop(save).
loop(skip, _) :- loop(skip).
loop(save, W) :- assertz(listitem(W)), loop(save).
test:
1 ?- loop(skip).
|: asd.
|: save.
|: ok.
|: ok1.
|: stop.
true
.
2 ?- listing(listitem).
:- dynamic stackoverflow:listitem/1.
stackoverflow:listitem(ok).
stackoverflow:listitem(ok1).
true.
Upvotes: 1
Reputation: 22803
This is some extremely confused code. Here's what you wanted:
:- dynamic listitem/1.
readline(Line) :-
% this is an SWI extension, but it's very handy
read_line_to_codes(user, Codes),
atom_codes(Line, Codes).
save :-
readline(X),
(X \= end -> (assertz(listitem(X)), save)
; true).
Odds are good, somewhere in the code you didn't bring, all you were missing was the effect of the ; true
there: that when you find end
, you're finished, but not that you failed. But you have a lot of problems here.
save/0
calls read/1
, which is a system predicate. All this is going to do is read a word from the user (ending with a period!) and notice that it isn't the word "save". Unfortunately, reading a whole line without periods at the end is a somewhat non-trivial task in Prolog, hence the pile of code in my solution.read/0
is not called by anything.X -> save(X)
is almost certainly not what you want. This is the first occurrence of X
in the predicate, and so it probably isn't doing you much good to test it conditionally before it has a value.end --> 'end'.
is a DCG rule, but you aren't using phrase/2
anywhere to invoke it (nor are you using end/2
directly with a difference list). assert/1
is a really bad habit to get into. The ISO predicates asserta/1
and assertz/1
are not only portable, they also give the reader a better idea what the effect on the fact database will be.dynamic
declaration for listitem/1
, which would raise portability and improve readability.Upvotes: 3