在Prolog (SWI)中,如何构建用户提供对的知识库并断言它们是相等的



我是Prolog的新手,正在努力学习。

对于我的程序,我想让用户提供"类型"的字符串对。

例如,用户在命令行提供字符串"john"one_answers"man"。这些原子将被制造成相等的,即约翰(人)。

在下一个提示符,然后用户提供"man"one_answers"tall",程序再次断言这些是有效的,man(tall)。

然后用户可以查询程序并问"john高吗?"或者在Prolog中:john(tall)通过传递性变为真。

我已经能够解析来自用户输入的字符串,并将它们分配给变量SubjectObject

我尝试了一个子句(其中主题和对象是不同的字符串):

attribute(Subject, Object) :-
   assert(term_to_atom(_ , Subject),
   term_to_atom(_ , Object)).

我想断言主语和宾语是有效的一对。如果用户断言它,那么它们属于一起。我如何使它们相等呢?

做这件事最好的方法是什么?

这类问题最近被问到很多(我猜你们的教授都分享了笔记之类的),所以浏览一下近代史可能对你有帮助。例如,我想到了这个。

你的代码太离谱了。这就是你要做的:
attribute(Subject, Object) :-
  Fact =.. [Object, Subject],
  assertz(Fact).

使用方法如下:

?- attribute(man, tall).
true.
?- tall(X).
X = man.
那么,关于这段代码,你应该注意以下几点:
  • 我们使用=../2,"univ"操作符,从列表构建结构。这是从一些原子中创建事实的唯一方法。
  • 我已经交换了主体和客体,因为这样做几乎肯定不是你想要的。
  • 您想要的谓词是assertz/1asserta/1,而不是assert/2。最后的a和z只是告诉Prolog你是想在数据库的开始还是结束。

基于查看您的代码,我认为您有很多包袱需要摆脱,以提高Prolog的效率。

  1. Prolog谓词不返回值。因此,assert(term_to_atom(...甚至不在正确的轨道上,因为您似乎认为term_to_atom将"返回"一个值,并且它将被替换为assert调用,就像在函数式或命令式语言中一样。Prolog的工作原理与此完全不同。
  2. 我不知道为什么你有一个空变量在你的term_to_atom谓词。我认为你这样做是为了满足谓词的性,但除非你有一个基本项和一个变量,否则这个谓词是相当无用的。
  3. 有一个assert/2,但它不做你想要的。应该很清楚为什么assert通常只接受一个参数。
  4. Prolog事实应该看起来像property(subject...)。构造事实然后查询它们并不容易,这是使用man(tall)必须做的。你想说的是有一个属性,是高的,man满足它。

我强烈建议你现在复习一下基本的Prolog教程。如果你想一意孤行,只会越走越远。

编辑:回应你的评论,我不确定你想要多一般。在基本情况下,你要处理一个4项列表,中间是[is,a],这就足够了:

build_fact([Subject,is,a,Object], is_a(Subject, Object)).

如果你想分离第一个和最后一个并创建事实,你必须再次使用univ:

build_fact([Subject|Rest], Fact) :-
  append(PredicateAtoms, [Object], Rest),
  atomic_list_concat(PredicateAtoms, '_', Predicate),
  Fact =.. [Predicate, Subject, Object].

不确定你是否想要忍受那些最后会结束的冠词("a", "the"):

?- build_fact([john,could,be,a,man], Fact).
Fact = could_be_a(john, man)

不要使用可变事实标题。当术语名称集固定时,Prolog工作得最好。相反,使用预定义的静态术语名创建一个通用位置来存储属性,例如:

is_a(john, man).
property(man, tall).
property(john, thin).

(考虑正常形式的SQL表)。然后您可以使用简单的assertz/1来更新数据库:

add_property(X, Y) :- assertz(property(X, Y)).

最新更新