Как увидеть все ответы в SWI-Prolog, не нажимая пробел?

Простой пример:

?- 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, чтобы увидеть следующий ответ, необходимо нажать пробел.

Как вывести все результаты на экран, не нажимая пробел?


Обратите внимание на аналогичный вопрос.

Если вы пришли к этому вопросу с помощью поиска и ваша настоящая проблема

Я использую SWI-Prolog и пытаюсь распечатать список, но если в списке более 9 элементов, это выглядит так:

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

есть ли способ показать весь список?

Тогда посмотрите эти вопросы и ответы:

SWI-Prolog - показать длинный список
SWI-Prolog, как показать весь ответ (список)?


person Guy Coder    schedule 17.01.2019    source источник
comment
Вы можете использовать between(1,10,X), print(X), nl, fail., чтобы механизм поиска с возвратом продолжал отправлять результаты в print(X) и nl, пока все не будут исчерпаны.   -  person Willem Van Onsem    schedule 18.01.2019
comment
Легкий! Вместо этого вы можете нажать точку с запятой!   -  person Daniel Lyons    schedule 18.01.2019
comment
@DanielLyons Нажатие точки с запятой у меня не работает.   -  person Guy Coder    schedule 18.01.2019
comment
В GNU Prolog при первом запросе решения вы можете нажать a, после чего отобразятся все остальные. Не уверен, что такое эквивалент в SWI (или есть ли он).   -  person lurker    schedule 18.01.2019
comment
@DanielLyons Вы должны опубликовать это как ответы для тех, кто не читает комментарии. Одна из причин, по которой я разместил вопрос, заключалась в том, что я не мог легко найти ответ, и я удивлен, что он не был помечен как дубликат. Я знаю, что видел это в других ответах, но не помню, чтобы видел это как отдельный ответ. Если вы опубликуете ответ, я проголосую за него. :)   -  person Guy Coder    schedule 18.01.2019
comment
@lurker Вы должны опубликовать это как ответы для тех, кто не читает комментарии. Одна из причин, по которой я разместил вопрос, заключалась в том, что я не мог легко найти ответ, и я удивлен, что он не был помечен как дубликат. Я знаю, что видел это в других ответах, но не помню, чтобы видел это как отдельный ответ. Если вы опубликуете ответ, я проголосую за него. :)   -  person Guy Coder    schedule 18.01.2019


Ответы (3)


"хакерское" решение состоит в том, чтобы добавить print(X), nl, fail к вызову. Здесь print(X), конечно, может напечатать любую соответствующую информацию. Например between(1,10,X), print(X), nl, fail.

Это работает, поскольку print/1 [swi-doc]< /a> — это просто еще один предикат, который печатает переданный ему термин. nl/0 [swi-doc] напечатает символ новой строки и fail/0 [ swi-doc] всегда терпит неудачу.

Таким образом, мы позволяем Прологу предлагать решения, печатать их, печатать новую строку, и fail «активирует» механизм поиска с возвратом, который будет стремиться искать другое решение, которое снова печатается и терпит неудачу.

В конце концов все решения печатаются, и, таким образом, вызов завершается ошибкой. Таким образом, это дает:

?- between(1,10,X), print(X), nl, fail.
1
2
3
4
5
6
7
8
9
10
false.
person Willem Van Onsem    schedule 17.01.2019

Учитывая (несколько) недавнее добавление библиотеки (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 против 1100) и влияние на мини-DSL.

изменить

Расширение uDSL с помощью приятного шаблона WillNess:

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

а потом

?- * between(1,3,N), write(N), nl.
1
2
3
true.
person CapelliC    schedule 18.01.2019

Шаблон кода (Goal, false ; true) известен как цикл, управляемый отказом.

Вы также можете написать bagof( _, Goal, _). Goal может выполнять некоторую печать, которая будет появляться постепенно или частями, если вывод буферизован. Обязательно экранируйте все свободные переменные в Goal (как A^B^C^Goal).

Вы можете запустить его как файл исходного кода Prolog в командной строке/подсказке оболочки и перенаправить его вывод в команду оболочки "more".

Или вы можете просто запустить свой запрос в приглашении Пролога и все время держать нажатой клавишу ;.

person Will Ness    schedule 18.01.2019
comment
(Goal, false ; true): хороший узор! - person CapelliC; 18.01.2019
comment
@CapelliC Я думал, что это широко известно... :) - person Will Ness; 18.01.2019
comment
Я знал о failure-driven loop, но никогда не видел, чтобы это делали так. - person Guy Coder; 18.01.2019
comment
@GuyCoder, как ты это видел? Мне просто любопытно. - person Will Ness; 18.01.2019
comment
which way was it (failure driven loop) that you saw? То, как Виллем Ван Онсем дал свой ответ с fail; Я надеюсь, что это считается failure driven loop, иначе мне придется делать больше заметок. - person Guy Coder; 18.01.2019
comment
Ну конечно; естественно. бит ; true - это просто украшение. теперь, когда я погуглил, homepages.inf.ed.ac.uk/ pbrna/prologbook/node95.html дает тоже с истинным в конце, только синтаксически другой. наверное, так я видел это в одной из старых книг. - person Will Ness; 18.01.2019