如何在不按空格键的情况下查看SWI-Prolog中的所有答案?

8

简单示例:

?- between(1,10,X).
X = 1 ;
X = 2 ;
X = 3 ;
X = 4 ;
X = 5 ;
X = 6 ;
X = 7 ;
X = 8 ;
X = 9 ;
X = 10.

当使用SWI-Prolog并使用REPL查看下一个答案时,需要按下空格键。

如何在不按下空格键的情况下将所有结果列出到屏幕上?


类似问题的注意事项。

如果您通过搜索找到了这个问题,并且您真正的问题是

I'm using SWI-Prolog and I'm trying to print a list but if the list has more than 9 items - it look like that -

[1, 15, 8, 22, 5, 19, 12, 25, 3|...] 

is there a way to show the whole list?

接下来看这些问答:

SWI-Prolog - 显示长列表
SWI-Prolog 如何显示整个答案(列表)?


1
你可以使用 between(1,10,X), print(X), nl, fail.,这样回溯机制会不断向 print(X)nl 提交结果,直到全部耗尽。 - Willem Van Onsem
1
很简单!你可以按分号代替! - Daniel Lyons
@DanielLyons 按分号键不起作用。 - Guy Coder
1
在GNU Prolog中,在第一个解决方案提示处,您可以按下“a”,然后它会显示所有剩余的解决方案。不确定SWI中的等效物是什么(或者是否存在)。 - lurker
@DanielLyons,你应该将其发布为答案,以便那些不阅读评论的人可以看到。我发出这个问题的部分原因是因为我无法轻松找到答案,并且很惊讶它没有被标记为重复。我知道我在其他答案中看到过这些注释,但不记得看到它作为一个独立的答案。如果你发布一个答案,我会给它点赞。 :) - Guy Coder
@lurker 你应该将这个作为答案发布,以便那些不读评论的人可以看到。我发出这个问题的部分原因是因为我无法轻松地找到答案,并且很惊讶它没有被标记为重复。我知道我在其他答案中看到过这些注释,但不记得看到它作为一个独立的答案。如果你发布一个答案,我会给它点赞。 :) - Guy Coder
3个回答

6
一个“hackish”的解决方案是在调用中添加print(X), nl, fail。这里的print(X)当然可以打印任何相关信息。例如:between(1,10,X), print(X), nl, fail
这个方法可以行得通,因为print/1 [swi-doc]只是另一个打印传递给它的项的谓词。nl/0 [swi-doc]会打印一个新行字符,而fail/0 [swi-doc]则总是失败。
因此,我们让Prolog提出解决方案,打印它们,打印一个新行,而fail将“激活”回溯机制,以寻找另一个解决方案,再次打印并失败。
最终,所有解决方案都被打印出来,因此调用失败。结果就是:
?- between(1,10,X), print(X), nl, fail.
1
2
3
4
5
6
7
8
9
10
false.

4

鉴于库(solution_sequences)的最新补充,特别是call_nth/2,今天你可以编写以下代码:

?- call_nth((between(1,4,X), writeln(X)), 100).
1
2
3
4
false.

当然,只关注前100个答案时要有一定的控制。
?- call_nth((between(1,4,X), writeln(X)), 2).
1
2
X = 2.

在使用call_nth/2之前,我使用的是forall/2:

?- forall(between(1,4,X), writeln(X)).
1
2
3
4
true.

编辑

鉴于 call_nth 和 forall 是二进制谓词,一些语法糖可以缩短REPL的代码。在 ~/.swiplrc 中添加如下内容:

:- op(100, xfx, (?*)).
Gen ?* Test :- forall(Gen, Test).

:- op(1100, xfx, (?+)).
Run ?+ Count :- call_nth(Run, Count).

然后重新启动swipl,现在就可以了。
?- between(1,4,X) ?* (S is X*X, writeln(square_of(X):S)).
square_of(1):1
square_of(2):4
square_of(3):9
square_of(4):16
true.

?- between(1,4,X), write(X), nl ?+ 2.
1
2
X = 2.

请注意不同的先决条件(100 vs 1100)及其对迷你DSL的影响。
编辑
使用WillNess的好模式扩展uDSL:
:- op(1100, fx, (*)).
(* Goal) :- (Goal, false ; true).

然后

?- * between(1,3,N), write(N), nl.
1
2
3
true.

3
(Goal, false ; true) 代码模式被称为“失败驱动循环”(failure-driven loop)。
你还可以编写 bagof( _, Goal, _)Goal 可以进行一些打印,逐步显示或分段显示(如果输出被缓冲)。请确保转义 Goal 中的所有自由变量(如 A^B^C^Goal)。
你可以在命令/Shell提示符下将其作为 Prolog 源代码文件运行,并将其输出重定向到“more” Shell 命令。
或者,你可以在 Prolog 的提示符下简单地运行查询,并一直按住你的 ; 键。

(Goal, false ; true): 不错的模式! - CapelliC
2
@CapelliC 我以为这是众所周知的... :) - Will Ness
我知道“失败驱动循环”,但从未见过像那样的实现。 - Guy Coder
@GuyCoder,你是用哪种方式看到的?我只是好奇。 - Will Ness
你看到的是哪种方式(失败驱动循环)?Willem Van Onsem在他的答案中提供了一种使用fail的方式;我希望这被认为是一种“失败驱动循环”,否则我将不得不做更多的笔记。 - Guy Coder
是的,当然。; true 部分只是装饰而已。现在我谷歌了一下,https://homepages.inf.ed.ac.uk/pbrna/prologbook/node95.html 也给出了以 true 结尾的写法,只是语法上略有不同。这可能是我在旧书中看到的方式。 - Will Ness

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接