【问题标题】:Prolog, error when querying a false statementProlog,查询错误语句时出错
【发布时间】:2014-01-25 00:05:36
【问题描述】:
input :-
read_line_to_codes(user_input, Input),
string_to_atom(Input,Atoms),
atomic_list_concat(Alist, ' ', Atoms),
phrase(sentence(S), Alist),
action(S).


statement(Rule) --> [Noun, 'is', 'a', Object], { Rule =.. [Object, Noun]}.
statement1(Rule) --> ['A', Noun, 'is', 'a', Object], { Rule =.. [Object, Noun]}.
query(Fact) --> ['Is', Noun, 'a', Object], { Fact =.. [Object, Noun]}.

sentence(statement(S)) --> statement(S).
sentence(statement1(S))--> statement1(S).
sentence(query(Q)) --> query(Q).


action(statement(S)) :- asserta(S) -> write(ok).
action(statement1(S)) :- asserta(S) -> write(ok).
action(query(Q)) :-( Q -> write(yes); write(unknown)), nl.

任务是根据用户输入以“_ is a _”形式创建规则。或“一个_是一个_。”这应该以“ok”响应。

然后可以查询“是_是_吗?”并回答“是”或“未知”。 如果谓词(我认为这就是所谓的“火腿”)不在数据库中,我不知道为什么它会出错,但是如果另一部分不在数据库中就可以了。关于我做错了什么的任何想法?对不起,如果我第一次用序言做一些愚蠢的事情。如果这很重要,我正在使用 SWI-Prolog V.6.2.6。我将如何在输出中省略 true 或 false 回报

   11 ?- input.
   |: john is a dog
   ok
   true .

   12 ?- input.
   |: Is john a dog
   yes
   true.


   13 ?- input.
   |: Is abraham a dog
   unknown
   false.

   14 ?- input.
   |: Is john a ham
   ERROR: action/1: Undefined procedure: ham/1
   Exception: (8) ham(john) ? 

【问题讨论】:

标签: prolog dcg


【解决方案1】:

首先,Prolog 响应的实际上是一个实现细节。 SWI 响应“true”,但其他一些实现响应“ok”。因此,只要您在应该得到肯定和否定的时候得到肯定和否定,您的代码就没有什么可以改变的。

其次,您的狗和火腿示例之间存在差异。处理完样本输入后查看数据库:

?- listing.
⋮ 
:- dynamic dog/1.

dog(john).
⋮

ham/1 在哪里?无处。当你asserta(dog(john)) 时,Prolog 会意识到dog/1 是一个谓词,但ham/1 从未发生过。因此,您必须确定该查询是否格式正确,在这种情况下您要捕获异常,或者使用dynamic/1 预先声明所有可能的谓词,或者对它的格式不正确感到高兴。您的使用场景将确定哪个是合适的。例如,您可以这样做:

?- [user].
|: :- dynamic ham/1.
|: % user://2 compiled 0.00 sec, 1 clauses
true.

?- input.
|: Is john a ham
false.

我怀疑你会想要对所有事情都这样做,所以你可能想看看 SWI-Prolog 的 catch facility。有关如何处理它的示例,请参阅此答案底部的编辑。

另外,我可能会稍微修改 DCG 以使其更通用和更简单:

article --> [a].
article --> [the].
article --> [].

noun(Noun) --> article, [Noun].

statement(Rule) --> noun(Noun), [is], noun(Object), { Rule =.. [Object, Noun] }.
query(Fact) --> ['Is'], noun(Noun), noun(Object), { Fact =.. [Object, Noun]}.

sentence(statement(S)) --> statement(S).
sentence(query(Q)) --> query(Q).

action(statement(S)) :- asserta(S).
action(query(Q)) :- Q.

另外,没有必要创建statement1。您可以拥有一个包含多个实体的 DCG 规则;即使您确实需要两个主体,也可以让它们都生成statement/1 结构以匹配action/1;您当然不需要将statement1/1 传播到代码的其余部分。

最后一句话,你不需要引用小写的原子。 :)

总的来说,我认为你在这里做得很好!这东西很难学,网上的资料也很少。我希望你能坚持下去,你可能已经开始看到 Prolog 和 DCG 可以做的很酷的事情了!

编辑:您可以通过将最后一个 action/1 子句替换为以下内容来捕获错误并正确处理:

action(query(Q)) :- 
    catch((Q -> write(yes) ; write(unknown)), 
          error(existence_error(procedure, _), _), 
          write(unknown)), 
    nl.

【讨论】:

  • 谢谢!是的,这是一项具有挑战性的任务。我们的教科书不包括序言,所以它更有趣!我必须抓紧时间,因为我无法预测 TA 会输入什么,但我不明白。
  • 把它想象成一个数据库。这是空表和不存在的表之间的区别。在一个存在的地方找不到东西就是生活。找不到您要查找的地方是错误的。
  • 所以应该是这样的... catch(:query(Q), +Catcher, :write(unknown)) ?这是什么“+捕手”?有没有办法在 SWI IDE 中关闭突出显示文本的自动复制?这非常烦人。
  • 我在答案中添加了一些代码来展示如何使用 catch。我不使用 SWI IDE,所以我无法帮助您。 Prolog 在语法方面非常简单;我通常使用 Emacs 或 Textadept 或 Textmate 或其他任何东西在一个窗口中编辑代码,然后在有意义的编辑后使用 make. 在 SWI 中重新加载它。
  • 该死,我很接近“action(query(Q)) :-catch(( Q -> write(yes)), Q, write(unknown))。”只是不知道第二条。谢了哥们!我真的很感激帮助。现在开始作业中真正困难的部分:(
猜你喜欢
  • 1970-01-01
  • 2018-10-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多