NLP PROLOG语法

时间:2018-05-16 21:14:55

标签: prolog nlp grammar

我们有正式的语言

G 1 = { V , T , S , P }, where
V = { S , E }
T = { x , y , z }
P = { S->E , E->xE , E->yE , E->z }

我们可以接受七个句子{xz,xy,xyz,xyxz,z,xxyz,Xyz}作为格式良好的公式吗?使用Prolog验证这一点。

这是我的代码:

s --> e.
e --> [x], e.
e --> [y], e.
e --> [z].

它只能识别s([z],R)。为什么呢?

?- s([z], R).
R = [].

?- s([xz], R).
false.

?- s([x], R).
false.

2 个答案:

答案 0 :(得分:3)

首先,正如@lurker在评论中已经指出的那样,在调用DCG时始终使用phrase/2phrase/3。其次,正如@TomasBy和@WillBeason指出的那样,你的DCG正在描述一个包含原子xyz的列表,用逗号分隔。因此,根据你的语法测试xz是否是一个实际的句子(我假设s代表什么),你会查询:

?- phrase(s,[x,z]).
true ;
false.
确实如此。现在让我们来看看最常见的查询,即问哪些句子?

?- phrase(s,S).
ERROR: Out of local stack

这不太顺利。原因是DCG规则的顺序:调用s//0导致调用e//0的第一个规则,再次递归调用e//0,也就是说,第一个规则e//0的循环继续,直到Prolog用完堆栈。所以让我们先把非递归规则改为规则的排序......

s --> e.

e --> [z].          % <- moved here from last position
e --> [x], e.
e --> [y], e.

...然后重试查询:

?- phrase(s,S).
S = [z] ;
S = [x, z] ;
S = [x, x, z] ;
S = [x, x, x, z] ;
.
.
.

现在我们正在获得实际的解决方案。因此,DCG规则的排序确实很重要。但是,答案的列表是不公平的,因为e//0的最后一个规则,即处理y的规则实际上从未被调用过。这可以通过为目标length/2添加前缀来解决。查询...

?- length(S,_).
S = [] ;
S = [_G3671] ;
S = [_G3671, _G3674] ;
S = [_G3671, _G3674, _G3677] ;
.
.
.

...产生具有所有可能长度的列表,因此将其添加到DCG调用之前,将使Prolog查找长度为0的所有解决方案,然后继续执行长度为1,然后继续执行长度为2,依此类推...... / p>

?- length(S,_), phrase(s,S).
S = [z] ;                    % <- solutions of length 1 from here
S = [x, z] ;                 % <- solutions of length 2 from here
S = [y, z] ;
S = [x, x, z] ;              % <- solutions of length 3 from here
S = [x, y, z] ;
S = [y, x, z] ;
S = [y, y, z] ;
S = [x, x, x, z] ;           % <- solutions of length 4 from here
.
.
.

所以你的语法实际上是产生任意长度的句子,应该如此。继续你的七个句子示例,如果你的应用程序需要限制列表的长度,你可以通过在你的查询中添加一个目标between/3来做到这一点......

?- between(1,3,N), length(S,N), phrase(s,S).
N = 1,
S = [z] ;
N = 2,
S = [x, z] ;
N = 2,
S = [y, z] ;
N = 3,
S = [x, x, z] ;
N = 3,
S = [x, y, z] ;
N = 3,
S = [y, x, z] ;
N = 3,
S = [y, y, z] ;
false.

...现在将产生包含最多3个单词的所有七个句子。请注意,您的示例{xz, xy ,xyz, xyxz ,z, xxyz xyz }并不完全正确你的语法描述的句子集。根据语法规则,元素 xy 根本不是句子。句子 xyxz xxyz 由您的语法指定,但要求最多长度至少为四个单词,这将产生十六个答案。七个句子中的最后一个, xyz ,在你的例子中出现两次,除非你的意思是...

?- phrase(s,[X,y,z]).
X = x ;
X = y ;
false.

......产生两个句子,第一个仍然构成重复。

最后,如果你真的迫切需要将原子作为答案,你可以改变DCG,将与xyz对应的代码放入列表而不是实际的原子。然后你可以使用atom_codes/2将句子作为单个原子而不是单词列表:

s --> e.

e --> [0'z].      % 0'z denotes the code corresponding to z
e --> [0'x], e.   % 0'x denotes the code corresponding to x
e --> [0'y], e.   % 0'y denotes the code corresponding to y

?- between(1,3,N), length(S,N), phrase(s,S), atom_codes(A,S).
N = 1,
S = [122],
A = z ;
N = 2,
S = [120, 122],
A = xz ;
N = 2,
S = [121, 122],
A = yz ;
N = 3,
S = [120, 120, 122],
A = xxz ;
N = 3,
S = [120, 121, 122],
A = xyz ;
N = 3,
S = [121, 120, 122],
A = yxz ;
N = 3,
S = [121, 121, 122],
A = yyz ;
false.

答案 1 :(得分:0)

(来自上述评论)

句子中的每个元素都需要以逗号分隔。字符串是以原子方式处理的,而不是字符序列。

?- s([x,z], R).
R = [] .

?- s([x,y,x,z], R).
R = [] .

?- s([x,y], R).
false.