我想创建一个谓词,它识别一个单词(在本例中为“save”)并开始保存下一个单词,直到符号/单词“end”出现。
它应该像这样工作:
?- save.
one
two
end
true.
保存的谓词:
save(X) :- assert(listitem(X)).
然后我就这样开始了:
save :- read(save).
read:- X -> save(X).
end --> 'end'.
问题是,我可以添加尽可能多的单词,但如果我想用“结束”停止命令,程序就会失败,实际上这些单词还没有被保存。
谓词的哪一部分是错的?我会很乐意得到一些帮助。 提前谢谢!
答案 0 :(得分:3)
这是一些非常混乱的代码。这就是你想要的:
:- 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).
赔率很好,在你没带的代码的某个地方,你所遗漏的只是; true
那里的效果:当你找到end
时,你已经完成了,但是没有你失败了。但是你在这里遇到很多问题。
save/0
调用read/1
,这是一个系统谓词。所有这一切都是从用户读取一个单词(以句点结束!)并注意它不是单词“save”。不幸的是,在Prolog中读取整行没有句点是一个有点不重要的任务,因此在我的解决方案中有一堆代码。read/0
没有被任何东西调用。X -> save(X)
几乎肯定不是你想要的。这是谓词中X
的第一次出现,因此在它有值之前有条件地测试它可能对你有好处。end --> 'end'.
是DCG规则,但您没有在任何地方使用phrase/2
来调用它(您也没有使用end/2
直接使用差异列表)。 assert/1
是一个非常糟糕的习惯。 ISO谓词asserta/1
和assertz/1
不仅是可移植的,它们还可以让读者更好地了解对事实数据库的影响。dynamic
没有listitem/1
声明,这会提高可移植性并提高可读性。答案 1 :(得分:1)
我会使用'状态机'方法:它很简单!
:- 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).
试验:
1 ?- loop(skip).
|: asd.
|: save.
|: ok.
|: ok1.
|: stop.
true
.
2 ?- listing(listitem).
:- dynamic stackoverflow:listitem/1.
stackoverflow:listitem(ok).
stackoverflow:listitem(ok1).
true.