8

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

peter.cyc
  • 1,763
  • 1
  • 12
  • 19
Guy Coder
  • 24,501
  • 8
  • 71
  • 136
  • 1
    You can use `between(1,10,X), print(X), nl, fail.` so the backtracking mechanism will keep submitting results to `print(X)` and `nl` until all are exhausted. – Willem Van Onsem Jan 17 '19 at 22:43
  • 1
    Easy! You can press semicolon instead! – Daniel Lyons Jan 17 '19 at 23:44
  • @DanielLyons Pressing semicolon is not working for me. – Guy Coder Jan 17 '19 at 23:51
  • 1
    In GNU Prolog, at the first solution prompt you can press `a` which will then show all the rest. Not sure what the equivalent is in SWI (or if there is one). – lurker Jan 18 '19 at 02:03
  • @DanielLyons You should post that as answers for others that don't read comments. Part of the reason I posted the question was because I couldn't easily find the answer and am surprised it has not been flagged as a duplicate. I know I have seen these noted in other answers, but don't recall seeing it as a stand alone answer. If you post an answer I will give it an up-vote. :) – Guy Coder Jan 18 '19 at 02:07
  • @lurker You should post that as answers for others that don't read comments. Part of the reason I posted the question was because I couldn't easily find the answer and am surprised it has not been flagged as a duplicate. I know I have seen these noted in other answers, but don't recall seeing it as a stand alone answer. If you post an answer I will give it an up-vote. :) – Guy Coder Jan 18 '19 at 02:07

3 Answers3

6

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.
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
4

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.
CapelliC
  • 59,646
  • 5
  • 47
  • 90
3

The (Goal, false ; true) code pattern is known as failure-driven loop.

You can also write bagof( _, Goal, _). The Goal can do some printing which will appear gradually, or in portions if the output is buffered. Be sure to escape all free variables in Goal (as A^B^C^Goal).

You can run this as a Prolog source code file at a command/shell prompt and redirect its output to a "more" shell command.

Or you can simply run your query at Prolog's prompt and keep your ; key pressed all the time.

Will Ness
  • 70,110
  • 9
  • 98
  • 181
  • `(Goal, false ; true)`: nice pattern! – CapelliC Jan 18 '19 at 15:36
  • 2
    @CapelliC I thought it was widely known... :) – Will Ness Jan 18 '19 at 16:21
  • I knew about `failure-driven loop` but have never seen it done like that. – Guy Coder Jan 18 '19 at 17:37
  • @GuyCoder which way was it that you saw? I'm just curious. – Will Ness Jan 18 '19 at 17:39
  • `which way was it (failure driven loop) that you saw?` The way Willem Van Onsem gave in his [answer](https://stackoverflow.com/a/54245495/1243762) with `fail`; I hope that is considered a `failure driven loop` otherwise I will have to make more notes. – Guy Coder Jan 18 '19 at 17:41
  • yes, of course. the `; true` bit is just decoration. now that I google it, https://homepages.inf.ed.ac.uk/pbrna/prologbook/node95.html gives it also with the true in the end, only different syntactically. that's probably how I saw it in one of the old books. – Will Ness Jan 18 '19 at 17:42