我正在学习Definite Clause Grammar,但我有一些问题需要理解Prolog如何将DCG规则转化为明确的条款。 例如,这里有一个写成DCG的小语法:
s --> np, vp.
np --> det, n.
vp --> v, np.
vp --> v.
det --> [the].
det --> [a].
n --> [woman].
n --> [man].
v --> [kisses].
如果我提出查询:
?-listing(s).
它回答我:
s(A,C) :-
np(A,B),
vp(B,C).
这是什么意思?为什么有两个论点?
此外,' C'这里的意思是:
det(A,B) :-
'C'(A,the,B).
谢谢!
答案 0 :(得分:5)
dcg使用了一个名为差异列表的概念。让我们假设您要进行解析(您也可以使用这些谓词生成列表,但现在让我们忽略它。)
如果您解析列表,例如[the,man,kisses,the,woman]
。您可以将此视为词汇,我借用"来自@Vikramnath Venkatasubramani的火车类比,所以归功于他/她。现在,如果我们拨打s([the,man,kisses,the,woman],C)
。 C
将返回[]
。
在每个谓词中会发生断开零,一个或多个货车的情况。所以它意味着:
s(A,C) :-
np(A,B),
vp(B,C).
np/2
会断开货车[the,man]
,导致它仍然存储剩余的火车B=[kisses,the,woman]
。现在,vp/2
会断开所有剩余的货车,导致C=[]
,一列空车。
如何实施
让我们考虑部分语法的实现。
s(A,C) :-
np(A,B),
vp(B,C).
np(A,B) :-
det(A,D),
n(D,B).
vp(B,C) :-
v(B,E),
np(E,C).
vp(B,C) :-
v(B,C).
det([the|W],W).
det([a|W],W).
n([woman|W],W).
n([man|W],W).
v([kisses|W],W).
如前所述,您致电np([the,man,kisses,the,woman],B)
,而np/2
必须断开构成名词短语的货车:[the,man]
。
np/2
和det/2
n/2
。现在det/2
会断开确定者的连接:the
,而n/2
会断开名词man
的连接,以使其更明确:
np([the,man,kisses,the,woman],[kisses,the,woman]) :-
det([the,man,kisses,the,woman],[man,kisses,the,woman]),
n([man,kisses,the,woman],[kisses,the,woman]).
现在det/2
不再重定向其职责,它实现为:
det([the|W],W).
现在我们进行模式匹配,这将基于:
det([the,man,kisses,the,woman],[man,kisses,the,woman]).
所以这意味着它已经断开了the
。
使用这种方法的优点是可以在恒定时间内完成断开连接。实际上,谓词并不知道列表的整个尾部。
此外,它允许断开事实中的多个单词。例如,您将名称添加为名词:
n([s,dallapalma|W],W).
在这种情况下n/2
将同时断开两辆货车。其他谓词不需要知道这一点,例如s/2
也不必决定它在np/2
和vp/2
之间分割火车的时间点:它允许{{1}断开尽可能多的货车,np/2
的目标是与列车的其余部分一起工作。