Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to see all of the answers in SWI-Prolog without pressing spacebar?

Simple example:

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

When this is done using SWI-Prolog using the REPL to see the next answer the spacebar has to be pressed.

How can all of the results be listed to the screen without pressing the spacebar?


Note on similar question.

If you arrived at this question by a search and your real problem is

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?

Then see these Q&A:

SWI-Prolog - show long list
SWI-Prolog how to show entire answer (list)?

like image 809
Guy Coder Avatar asked Jan 17 '19 22:01

Guy Coder


2 Answers

A "hackish" solution is to add print(X), nl, fail to the call. Here print(X) can of course print any relevant information. For example between(1,10,X), print(X), nl, fail.

This works since print/1 [swi-doc] is just another predicate that prints the term that is passed to it. nl/0 [swi-doc] will print a new line character, and fail/0 [swi-doc] always fails.

We thus let Prolog to propose solutions, print these, print a new line, and the fail will "activate" the backtracking mechanism that will aim to look for another solution that is again printed and fails.

Eventually all solutions are printed, and thus then the call fails. This thus yields:

?- between(1,10,X), print(X), nl, fail.
1
2
3
4
5
6
7
8
9
10
false.
like image 52
Willem Van Onsem Avatar answered Oct 02 '22 19:10

Willem Van Onsem


Given the (somewhat) recent addition of library(solution_sequences), and notably call_nth/2, today you could write

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

of course, when interested in just the first 100s answers. A bit of control:

?- call_nth((between(1,4,X), writeln(X)), 2).
1
2
X = 2.

Before call_nth/2, I was using forall/2:

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

edit

given that call_nth and forall are binary predicates, a bit of syntax sugar can shorten a bit the REPL: in ~/.swiplrc add

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

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

then restart swipl, and now

?- 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.

Note the different precedences (100 vs 1100) and the effect on the mini DSL.

edit

Extending uDSL with WillNess' nice pattern:

:- op(1100, fx, (*)).
(* Goal) :- (Goal, false ; true).

and then

?- * between(1,3,N), write(N), nl.
1
2
3
true.
like image 35
CapelliC Avatar answered Oct 02 '22 20:10

CapelliC