我正在尝试在prolog中编写一些dcg语法来描述语言
a^nb^n n>=0
"",ab,aabb,aaabbb itd
我写的所有内容都是
s --> slowo.
slowo --> [a],slowo,[b],!.
slowo --> [].
只要我想要做的只是检查单词是否正确,它的好处是什么,但是如果?-phrase(s,X)
能够生成我语言中的所有单词,那么dcg语法应该如何查找prolog?
答案 0 :(得分:3)
除了@Mog的答案之外,让我们考虑一般情况:
如果语法如此复杂,重新排序DCG规则将无济于事?我们怎样才能列举所有句子?如果语法以这种方式表达,它终止一个固定长度,我们得到所有句子
?- length(Xs, N), phrase(s, Xs).
单独的目标length
将以公平的方式列举所有列表。也就是说,从最短的[]
开始,枚举所有列表:
?- length(Xs, N). Xs = [], N = 0 ; Xs = [_G307], N = 1 ; Xs = [_G307, _G310], N = 2 ; Xs = [_G307, _G310, _G313], N = 3 ; Xs = [_G307, _G310, _G313, _G316], N = 4 ; ...
现在,长度固定,目标phrase(s, Xs)
将找到该固定长度的所有答案。举个例子,看看Mat对this grammar的回答。
因此,这是检查语法句子的一般方法。但是 - 这种普遍性需要付出代价!对于句子数量有限的语法,out方法不会终止:
:- use_module(
library(double_quotes)
).
s --> "a"|"b".
?- phrase(s, Xs). Xs = "a" ; Xs = "b".
这个语法开箱即用,但我们现在得到length/2
:
?- length(Xs, N),phrase(s, Xs). Xs = "a", N = 1 ; Xs = "b", N = 1 ; **loops**
此方法通常称为iterative deepening,尽管此术语更精确地强加了派生深度的约束。但我们对实际的“输出”施加了约束力。因此,迭代加深也能够处理左递归,而length/2
仅适用于以固定输入长度终止的语法。
这项技术在Prolog中特别有趣的原因在于它与Prolog的时间顺序回溯机制完美融合。
答案 1 :(得分:2)
在SWI Prolog中,我可以使用:
s(X, []).
或
phrase(s, X).
(正如你的建议)获取所有字符串。但是,为了在没有堆栈溢出的情况下生成任何答案,我需要颠倒slowo
的两个规则的顺序,并从递归规则中删除剪切。
答案 2 :(得分:2)
如果您是从Prolog开始,请尽量避免使用!/0
。没有它,你通常可以做得更好。
例如,您的语法可以写成如下:
s --> [].
s --> [a], s, [b].
并查询如下:
?- phrase(s, X).
请注意,prolog子句从左到右,从上到下被选中,因此在涉及回溯时,优先考虑写在另一个的顶部的规则。