简体   繁体   English

prolog dcg限制

[英]prolog dcg restriction

I would like to use DCGs as a generator. 我想用DCG作为发电机。 As of now, the syntax is 截至目前,语法是

s-->a,b.
a-->[].
a-->a,c.
c-->[t1].
c-->[t2].
b-->[t3].
b-->[t4].

I would like to generate all s where the length of a is < someNumber . 我想生成a的长度为< someNumber所有s

Using ?- phrase(a,X),length(X,Y),Y<4. 使用?- phrase(a,X),length(X,Y),Y<4. i can get all a with less than 4 items. 我可以得到所有a少于4项。 However, when all combinations are exhausted, the system (SWI-Prolog 6.2.5) seems to stall. 但是,当所有组合都用尽时,系统(SWI-Prolog 6.2.5)似乎停滞不前。 Sometimes ago, a similar question was asked here . 有时候, 这里提出了类似的问题。 However, being new to Prolog i am not able to make it work with the grammar above. 但是,作为Prolog的新手,我无法使用上面的语法。 Any ideas? 有任何想法吗?

Update: There was a comment by (canrememberthename) which got deleted, somehow. 更新:(canrememberthename)有一个评论被删除,不知何故。 Anyway, it was suggested to use between(1,4,Y),length(X,Y),phrase(a,X). 无论如何,建议between(1,4,Y),length(X,Y),phrase(a,X). to set limits. 设定限制。 This worked nicely, after changing my code to a-->c,a. 将代码更改a-->c,a.这很好a-->c,a.

The first steps into Prolog are often a bit difficult. 进入Prolog的第一步往往有点困难。 But you are on the right track: 但是你走在正确的轨道上:

Currently, your problem is that you get some answers/solutions as expected but then the system stalls ; 目前,您的问题是您得到了一些预期的答案/解决方案,但随后系统停滞不前; in fact, it is in an infinite loop. 事实上,它处于无限循环中。 You found that out by patiently hitting SPACE . 你通过耐心地击中SPACE找到了。 That might work with a tiny set of solutions but it will be tedious with a larger one. 这可能适用于一小部分解决方案,但如果使用较大的解决方案则会很繁琐。 Just think of looking at all sentences shorter than 20. 想想看看所有短于20的句子。

There is a simple keyboard and carpal tunnel friendly way to simulate hitting space: Simply add a goal false at the end like so: 有一个简单的键盘和腕管友好的方式来模拟击球空间:只需在最后添加一个false目标,如下所示:

?- phrase(a,X),length(X,Y),Y<4, false.

What could Prolog answer to such a question? Prolog能回答这个问题吗? Since there is false at the end, Prolog has not much choice: Either it answers false itself ; 由于最后有false ,Prolog没有太多选择:它要么自己回答false ; or it loops (or produces an error or produces some side-effect). 或者它循环(或产生错误或产生一些副作用)。 And in this case, it loops. 在这种情况下,它循环。

Now, we can narrow down the problem, by adding further false goals into your program. 现在,我们可以通过在您的程序中添加更多false目标来缩小问题范围。

?- phrase(a,X),length(X,Y),false, Y<4, false.
**LOOPS**

To make this better readable, I will only use one false goal and strike through the remaining part of the query: 为了使其更易于阅读,我将只使用一个false目标并查看查询的其余部分:

?- phrase(a,X),length(X,Y),false, Y<4.
**LOOPS**

Let's reduce that even further: 让我们进一步减少:

?- phrase(a,X),false,length(X,Y),Y<4.
**LOOPS**

They all loop! 他们都循环! But we get some interesting insight: Since these false -adorned queries do not terminate, also the original program does not terminate. 但是我们得到了一些有趣的见解:由于这些false查询不会终止,原始程序也不会终止。 So when you look at a query, and the very first goal does not terminate for itself, it follows that the entire query will not terminate (see the fine print at the end for more). 因此,当您查看查询,并且第一个目标不会自行终止时,整个查询将不会终止(请参阅最后的细则以获取更多信息)。

Therefore: You have to address the first goal somehow ! 因此:你必须以某种方式解决第一个目标!

My first attempt is to exchange length and phrase : 我的第一次尝试是交换lengthphrase

?- length(X,Y), phrase(a,X), Y<4.

Will this work? 这会有用吗? Just look at the first goal which loops: 只看循环的第一个目标:

?- length(X,Y), false, phrase(a,X), Y<4.

So this again will not terminate. 所以这再次不会终止。

You have to change the program again: 您必须再次更改程序:

?- between(1,3,Y), length(X,Y), false, phrase(a,X).
false.

So this terminates. 所以这终止了。 And if there will be a termination problem, phrase(a,X) has now to take the blame: 如果有终止问题, phrase(a,X)现在应该承担责任:

?- between(1,3,Y), length(X,Y), phrase(a,X), false.
**LOOPS**

You might be tempted to look at actual answers: 你可能想看看实际的答案:

?- between(1,3,Y), length(X,Y), phrase(a,X).
Y = 1,
X = [t1] ;
Y = 1,
X = [t2] ;
ERROR: Out of local stack

And you might conclude that this behavior is worse than your original definition. 您可能会得出结论,这种行为比您原来的定义更糟糕。 After all, we have now less answers than before. 毕竟,我们现在的答案比以前 But exactly that kind of reasoning does not help you to improve termination: With false both are of the same kind of incorrectness and you have to address this first . 但究竟那种推理不帮你改善终止:用false 都是同一种不正确的,你必须解决这个问题。 So by hiding the answers you can better concentrate on the rest. 因此,通过隐藏答案,您可以更好地专注于其余部分。

But why is your grammar problematic? 但为什么你的语法有问题呢? We can continue with our technique to insert goals false to narrow it down. 我们可以继续使用我们的技术来插入目标false以缩小范围。 But this time within your grammar. 但是这次你的语法。 Your program adorned with goals false is called a . 您的目标装饰为false ,称为

Just a practical remark: When I insert goals false into your program, I will save the program and type make in SWI: In this manner the program is rapidly recompiled. 只是一个实用的评论:当我在你的程序中插入false时,我将保存程序并在SWI中输入make :以这种方式快速重新编译程序。

After trying a bit, I got the following minimal failure-slice. 尝试了一下之后,我得到了以下最小的失败切片。 Note that within a DCG, false has to be written as {false} . 请注意,在DCG中, false必须写为{false}

?- between(1,3,Y), length(X,Y), phrase(a,X), false

s--> {false}, a,b.

a-->[], {false}.
a-->a,{false},  c.

c-->{false}, [t1].
c-->{false}, [t2].

b-->{false}, [t3].
b-->{false}, [t4].

Almost all your codebase are belong to false ! 几乎所有代码库都属于false So you have to address the tiny visible remaining part. 所以你必须解决微小的可见剩余部分。 It would be pointless to change something somewhere else. 在其他地方改变一些东西是毫无意义的。 This a --> a, ... must be changed! 这个a --> a, ...必须改变! And in fact changing it to a --> c, s solves the problem. 事实上将其改为a --> c, s解决了这个问题。

Why did you write a --> a, c. 你为什么写a --> a, c. in the first place? 首先? I suspect that you wanted to enumerate all solutions in a fair manner. 我怀疑你想以公平的方式列举所有解决方案。 The new version doesn't: 新版本没有:

?- phrase(a,X).
X = [] ;
X = [t1] ;
X = [t1, t1] ;
X = [t1, t1, t1] ;
X = [t1, t1, t1, t1] ;
X = [t1, t1, t1, t1, t1] ;
X = [t1, t1, t1, t1, t1, t1] ;
X = [t1, t1, t1, t1, t1, t1, t1] ...

That looks very intimidating. 这看起来非常令人生畏。 In fact, it looks wrong. 事实上,它看起来是错误的。 Doesn't it? 不是吗? But don't let you confuse by this: We have here an infinite set of sentences. 但是不要让你混淆:我们这里有无限的句子。 So the only correct response by Prolog is to produce infinitely many answers. 所以Prolog唯一正确的回答是产生无限多的答案。 For, if they would be finite, some list would be missing! 因为,如果它们是有限的,一些列表将会丢失! But of course, you want to see them enumerated in a fair manner. 但是,当然,你希望以公平的方式列举它们。 To get this, simply write: 要得到这个,只需写:

?- length(X,N),  phrase(a,X).
X = [],
N = 0 ;
X = [t1],
N = 1 ;
X = [t2],
N = 1 ;
X = [t1, t1],
N = 2 ;
X = [t1, t2],
N = 2 ;
X = [t2, t1],
N = 2 ;
X = [t2, t2],
N = 2 ;
X = [t1, t1, t1],
N = 3 ...

This is a major point in Prolog programs: Always go for the best (possible) termination property first. 这是Prolog计划的一个重点:始终首先寻找最好的(可能的)终止财产。 And do not look at the precise order how Prolog enumerates answers. 并且不要看Prolog如何列举答案的准确顺序。 For, if a program has better termination properties, it is next-to-trivial to use it to enumerate all solutions in a fair manner. 因为,如果一个程序具有更好的终止属性,那么使用它以公平的方式枚举所有解决方案是非常重要的。 But: A program that enumerates infinitely many solutions in a fair manner at the expense of termination cannot be used in more interesting cases. 但是:以更公平的方式列举无限多个解决方案而牺牲终止的程序不能用于更有趣的情况。

Fine Print 印刷精美
See this answer . 看到这个答案

the nonterminal a//0 is both left recursive and 'epsilon' (generate the empty sequence), and phrase/2 will loop immediately after the empty production. 非终结a // 0 既是递归的又是'epsilon'(生成空序列),短语/ 2将在空产生后立即循环。

You can solve your problem bounding list' length: 您可以解决问题边界列表的长度:

?- between(1,4,Y),length(X,Y),phrase(a,X).

and, as you have already done, removing the left recursion. 并且,正如您已经完成的那样,删除左递归。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM