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

时间:2017-12-09 00:41:48

标签: prolog dcg

我正在编写一个DCG,它会采用u2v形式的字符串,其中uv不必具有相等的长度和{{{ {}}中的{1}}必须与0u的数量相同。

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

1

我可以获得查询v的正确答案:

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).之后终止。相反,它只是重复这些答案。我对Prolog的了解非常有限,而且我主要是从LPN自学,所以我猜这更像是一个让我无法理解Prolog如何评估这些事情的问题。如果有人能解释为什么它不会终止,那将是最有帮助的。

2 个答案:

答案 0 :(得分:2)

多么有趣的问题!

我想到的是你想要利用你的语法结构。例如,要匹配括号,您必须按照以下方式执行某些操作:

expr --> [].
expr --> ['('], expr, [')'].

这样,你可以在parens之间找到任何东西,或者你每次都有一个左一个正确的paren。

我没有看到用这个问题实现这种崩溃的明显方法。可能有办法,但我不知道它是什么。然而,由于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//1v//1具有相同的结构:首先,匹配任何内容的基本情况,然后是与所需数字匹配的归纳情况并递增计数,Peano风格(0,s( 0),s(s(0)),s(s(s(0))),...),然后是一个与其他数字匹配的备用归纳案例,并向前传播前一个计数。

有可能用succ/2而不是这个来做这件事,但是我担心在哪里需要放置一些纯Prolog才能让它成为现实。和Peano一起走这条路似乎对我来说更简单。 (甚至可能采用clpfd方法。)

无论如何,我希望这有帮助!

答案 1 :(得分:1)

在我看来,OP假设输入中只出现0s,1s和2s。在这个假设下,这是Daniel Lyons的建议的变体:

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.

我承认我太新了,不明白为什么我不会'真实'。结果。