NLP PROLOG语法
NLP PROLOG 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.
(来自上面的评论)
句子中的每个元素都需要用逗号分隔。字符串以原子方式处理,而不是字符序列。
?- s([x,z], R).
R = [] .
?- s([x,y,x,z], R).
R = [] .
?- s([x,y], R).
false.
首先,正如@lurker 在评论中指出的那样,在调用 DCG 时始终使用 phrase/2
或 phrase/3
。其次,正如@TomasBy 和@WillBeason 所指出的,您的 DCG 正在描述一个包含原子 x
、y
和 z
的列表,并用逗号分隔。因此,要根据您的语法测试 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 在移动到长度 1 之前查找长度为 0 的所有解决方案,然后再移动到长度 2,依此类推。 .
?- 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 由您的语法指定,但要求最大长度至少为四个单词,这将产生 16 个答案。七个句子中的最后一个 xyz 在您的示例中出现了两次,除非您指的是查询...
?- phrase(s,[X,y,z]).
X = x ;
X = y ;
false.
... 产生两个句子,第一个句子仍然是重复的。
最后,如果你真的急需得到原子作为答案,你可以修改DCG,将x
、y
和z
对应的代码放入列表中而不是实际的原子。然后您可以使用 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.
我们有正式的语言
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.
(来自上面的评论)
句子中的每个元素都需要用逗号分隔。字符串以原子方式处理,而不是字符序列。
?- s([x,z], R).
R = [] .
?- s([x,y,x,z], R).
R = [] .
?- s([x,y], R).
false.
首先,正如@lurker 在评论中指出的那样,在调用 DCG 时始终使用 phrase/2
或 phrase/3
。其次,正如@TomasBy 和@WillBeason 所指出的,您的 DCG 正在描述一个包含原子 x
、y
和 z
的列表,并用逗号分隔。因此,要根据您的语法测试 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 在移动到长度 1 之前查找长度为 0 的所有解决方案,然后再移动到长度 2,依此类推。 .
?- 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 由您的语法指定,但要求最大长度至少为四个单词,这将产生 16 个答案。七个句子中的最后一个 xyz 在您的示例中出现了两次,除非您指的是查询...
?- phrase(s,[X,y,z]).
X = x ;
X = y ;
false.
... 产生两个句子,第一个句子仍然是重复的。
最后,如果你真的急需得到原子作为答案,你可以修改DCG,将x
、y
和z
对应的代码放入列表中而不是实际的原子。然后您可以使用 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.