我目前有一个包含几个人和一些关系谓词的小型 Prolog 数据库。例如:
female(anna).
female(susan).
male(john).
male(timmy).
siblings(anna, susan).
siblings(anna, john).
siblings(susan, john).
sibling(X, Y) :- siblings(X, Y) ; siblings(Y, X).
%X is brother of Y
brother(X, Y) :- male(X), sibling(X, Y).
Run Code Online (Sandbox Code Playgroud)
而且我有一个 DCG 可以确定有效的问题,例如“谁是约翰的兄弟”,这也很有效。
question --> ip, verb, article, noun, pronoun, name.
Run Code Online (Sandbox Code Playgroud)
现在我想让我的程序用这样的名词和名字来调用我的家庭数据库:
noun(X, name).
Run Code Online (Sandbox Code Playgroud)
在这个例子中应该是
brother(X, anna).
Run Code Online (Sandbox Code Playgroud)
然后将答案作为自然语言答案返回,例如:
"the brother of anna is john"
Run Code Online (Sandbox Code Playgroud)
定义答案句的语法也没有问题。我唯一不知道的是,如何从我的 DCG 调用到我的数据库并在其中填充正确的值。我现在环顾四周 - 也许我不知道正确的搜索词 - 并且找不到与此相关的内容。
我希望你们有一些好主意!:)
谢谢你。
{}/1
使用非终结符{}//1
从 DCG 中调用任意 Prolog 目标。
例如:
verb --> [V], { verb(V) }.
Run Code Online (Sandbox Code Playgroud)
这定义了一个非终结符verb//1
。此DCG描述了由该组件的列表V
,使得verb(V)
成立,其中verb/1
是一个正常的Prolog谓词。
请注意,还有第二种方法可以做到这一点,从某种意义上说,它更容易理解:您可以简单地将所有内容都转换为 DCG 非终结符!
例如,你可以说:
female(anna) --> [].
female(susan) --> [].
male(john) --> [].
male(timmy) --> [].
Run Code Online (Sandbox Code Playgroud)
然后您可以直接使用这些非终结符。您可以定义自动term_expansion/2
执行此类转换的规则。
在您的特定情况下,使用{}/1
可能更可取,因为您已经拥有现有的 Prolog 事实和。但是在某些情况下,最好始终使用 DCG。
编辑:从您的评论中,我看到您的问题涉及更多。
问题是关于:
这是非常直接的:本质上,您只需要描述您想要的 Prolog 目标和相应句子之间的关系。
我们通过向 DCG 引入一个新参数来实现这一点,该参数将表示需要执行以回答句子的 Prolog 目标。在您的示例中,您希望将句子“谁是苏珊的兄弟?”与 Prolog 谓词的调用相关联brother(X, susan)
。您已经有一个sentence//0
描述此类句子的非终结符。你只需要明确这些句子对应的目标。例如:
sentence_goal( noun(X, name) ) --> ip, v, a, noun, p, name.
这仅用于说明原理;我并不是说这已经是完整的解决方案。重点只是表明您可以以与所有其他术语完全相同的方式推理 Prolog 目标。
然后,您可以分两个阶段调用实际目标:
sentence_goal//1
call/1
直接使用或调用它。例如:
?- phrase(sentence_goal(Goal), Sentence), Goal.
Run Code Online (Sandbox Code Playgroud)
在您的情况下,剩下的就是将这些句子与您要调用的 Prolog 目标相关联,例如brother_of/2
等等。
这一切都不需要任何副作用(write/1
)!相反,专注于描述句子和目标之间的关系,让 Prolog 顶层为您打印。