为包含相同数量特定数字的字符串写入DCG-Prolog

为包含相同数量特定数字的字符串写入DCG-Prolog,prolog,dcg,Prolog,Dcg,我正在编写一个DCG,它将以u2v的形式接受字符串,其中u和v不必长度相等,并且u中0的数量必须与v中1的数量相同 到目前为止,我已经能够在纸上写下几个语法,但当我编写它们并尝试查询时,我通常会在某个地方出现一个循环。这是我能得到的最接近的结果: s-->[2]. s-->u,[0],n. s-->u,s,v. n-->s,[1],v. u-->[1],u. u-->[]. v-->[0],v. v-->[]. 我可以得到查询s([0,1,1,2

我正在编写一个DCG,它将以
u2v
的形式接受字符串,其中
u
v
不必长度相等,并且
u
0
的数量必须与
v
1
的数量相同

到目前为止,我已经能够在纸上写下几个语法,但当我编写它们并尝试查询时,我通常会在某个地方出现一个循环。这是我能得到的最接近的结果:

s-->[2].
s-->u,[0],n.
s-->u,s,v.
n-->s,[1],v.
u-->[1],u.
u-->[].
v-->[0],v.
v-->[].
我可以得到查询
s([0,1,1,2,0,0,1,0],N)的正确答案。
这将是:

N = [] ;
N = [0]

但它不会像应该的那样以
false
after结尾。相反,它只是重复这些答案。我对Prolog的了解非常有限,而且我主要是从LPN自学的,所以我猜这更多的是因为我不了解Prolog是如何评估这类事情的。如果有人能解释为什么它不会终止,那将非常有帮助。

多么有趣的问题

我马上想到的是,你想利用你的语法结构。例如,要匹配括号,您必须按照以下步骤进行操作:

expr --> [].
expr --> ['('], expr, [')'].
这样的话,要么你有一个左右排列的排列,要么你每次都有一个左右排列

我看不出一个明显的方法来解决这个问题。也许有办法,但我不知道是什么。然而,由于Prolog变量的工作方式,DCG几乎具有超自然的能力在解析中的不同位置之间传播信息,这是通过为DCG规则创建参数实现的,如下所示:

rule(Stuff) --> ...
无论如何,下一个麻烦是你想数数,这意味着可能会涉及到算术。然而!我们可以通过使用Peano数字来进行一些欺骗,因为我们真正关心的是它们在两边恰好相等,所以我们不需要将结果传递给用户

不用多说,下面是我提出的解决方案:

u2v    --> u2v(_).
u2v(N) --> u(N), [2], v(N).

u(0)    --> [].
u(s(N)) --> [0], u(N).
u(N)    --> [X], { member(X, [1,2,3,4,5,6,7,8,9]) }, u(N).

v(0)    --> [].
v(s(N)) --> [1], v(N).
v(N)    --> [X], { member(X, [0,2,3,4,5,6,7,8,9]) }, v(N).
我确信有更好的方法来编写这段代码(甚至可能有完全优越的方法),但这一种似乎在我有限的测试中起作用。它甚至会生成,除了双方讨厌的无界递归

解决方案的关键是这一行:

u2v(N) --> u(N), [2], v(N).
事实上,您不需要保留
N
,但我发现它对调试很有用。这里最重要的是
u(N)
匹配
v(N)
。然后
u//1
v//1
都有相同的结构:首先是不匹配的基本情况,然后是匹配所需数字并递增计数的归纳情况,Peano风格(0,s(0),s(0)),s(s(0)),…),然后是另一个与其他数字匹配的感应情况,并向前传播上一个计数

也许可以用
succ/2
来代替这个,但我担心需要将纯Prolog的一部分放在哪里才能让它运行。和皮亚诺走这条路对我来说似乎更简单。(甚至可能有一种clpfd方法。)


不管怎样,我希望这有帮助

在我看来,OP假设输入中只出现0、1和2。基于这一假设,这里是丹尼尔·莱昂斯建议的一个变体:

u2v --> u(N),[2],v(N).

u(0) --> [].
u(N) --> [1], u(N).
u(N) --> [0], u(N1), { N1 #= N - 1 }.

v(0) --> [].
v(N) --> [0], v(N).
v(N) --> [1], v(N1), { N1 #= N - 1 }.
OP的测试用例在SWI Prolog 7.6.4中产生了这一点:

?- phrase(u2v, [0,1,1,2,0,0,1,0]).
true ;
false.
我承认,我在这方面太新了,无法理解为什么我不能得到“真的”。结果是。

你有一个循环
s-->n,n-->s