在语法规则(dcg)中,有几个预定义的结构:(',')//2
含义连接、('|')//2
含义交替等。一个由多个但不是所有 Prolog 系统支持的结构是(\+)//1
.
就个人而言,我只是为了使用它而使用它。我从未在其他人编写的代码中看到它。
那么,是否有合法用途(\+)//1
?
编辑:此外,在带有未实例化变量(\+)//1
的查询中是否有合法用途。phrase(nt, L)
L
在语法规则(dcg)中,有几个预定义的结构:(',')//2
含义连接、('|')//2
含义交替等。一个由多个但不是所有 Prolog 系统支持的结构是(\+)//1
.
就个人而言,我只是为了使用它而使用它。我从未在其他人编写的代码中看到它。
那么,是否有合法用途(\+)//1
?
编辑:此外,在带有未实例化变量(\+)//1
的查询中是否有合法用途。phrase(nt, L)
L
\+ 可用于创建不那么模棱两可的语法。使用 \+ 的优势!例如,是 \+ 的某种声明性,因此可以重新排序生成的 DCG 规则。
让我们举个例子,考虑以下语法:
s([X|Y]) --> t(X), s(Y). % 1
s([]) --> []. % 2
t(2) --> [a,a]. % 3
t(1) --> [a]. % 4
上面的语法是高度模棱两可的,例如我得到了以下输入的多个解析:
?- phrase(s(A),[a,a,a,a,a]).
A = [2,2,1] ;
A = [2,1,2] ;
A = [2,1,1,1] ;
etc..
现在假设我更喜欢 t 的长解析而不是 t 的短解析。我可以通过以下方式进行切割:
t(2) --> [a,a], !. % 5
t(1) --> [a]. % 6
?- phrase(s(A),[a,a,a,a,a]).
A = [2,2,1] ;
No
不幸的是,我无法重新订购。由于执行以下操作不会产生预期的结果。尽管 s(A) 现在以不同的顺序产生结果,但我们又回到了第一方,因为文法又是模棱两可的:
t(1) --> [a]. % 7
t(2) --> [a,a], !. % 8
?- phrase(s(A),[a,a,a,a,a]).
A = [1,1,1,1,1] ;
A = [1,1,1,2] ;
A = [1,1,2,1] ;
etc...
现在让我们尝试使用 \+。我们可以用下面的否定来代替cut:
t(2) --> [a,a]. % 9
t(1) --> [a], \+ [a]. % 10
?- phrase(s(A),[a,a,a,a,a]).
A = [2,2,1] ;
No
现在让我们试试是否可以重新排序。我们对t//1的语法规则重新排序:
t(1) --> [a], \+ [a]. % 11
t(2) --> [a,a]. % 12
?- phrase(s(A),[a,a,a,a,a]).
A = [2,2,1] ;
No
声明性非常有用。例如,这意味着我们可以在从右到左的图表解析器中使用 \+,它以任意顺序选择语法规则。声明性确保图表解析器的自下而上的前向链接产生相同的结果,而与 DCG 规则的输入顺序无关。
然后可以将 DCG 技术应用到大型自然语言 (NL) 项目中,并且可以很好地扩展。NL 语法可以根据经验调整为确定性。一个语法越确定,它的解析效率就越高。原本难以处理的复杂 NL 语法变得可行。
再见
当 L 未被实例化时,该文法将用于文本生成。那么你根本不需要语法 \+ 。由于某些文本不再存在歧义问题。
让我们举个例子,考虑以下语法:
s([X|Y]) --> t(X), s(Y). % 1
s([]) --> []. % 2
t(2) --> [a,a]. % 3
t(1) --> [a]. % 4
每个不同的解析都有不同的解析树。并且使用短语/2 生成文本没有歧义。以下查询恰好给出了一个答案:
?- phrase(s([2,1]),L).
L = [a,a,a]
?- phrase(s([1,2]),L).
L = [a,a,a]
?- phrase(s([1,1,1]),L).
L = [a,a,a]
但是有一点重用的问题。假设我有一个带有 \+ 用于解析的 NL 语法。然后我不能用它来解析。由于 \+ 目标的实例化模式会有所不同,因此构造的语义会发生变化。
出路可能只是使用两种语法。一个用于解析,一个用于反解析。我猜解析和反解析是两种不同的认知能力。记得在学校里,有阅读练习和写作练习。计算机科学领域也是如此。
我认为在某些情况下也可以使用单个语法,并将 \+ 视为消歧的注释,在 unparse 期间删除或以不同方式处理。可以建立这样一种机制。但与解析相比,反解析的问题更深:辅助条件的双向性 ({}/1)、反解析期间的左递归等……
再见