Можете ли вы написать между 3 в чистом прологе?

Я пытался понять, как создать серию значений из предиката Prolog при обратном отслеживании. Встроенный предикат between/3 будет генерировать все целые числа в диапазоне по одному на обратном пути, поэтому пример того, как это написано, может помочь мне с моей задачей.

Я искал реализацию в существующей системе Prolog, но реализация between/3 для GNU Prolog - это функция C, и трюк заключается в том, что она вызывает другую функцию C "Pl_Create_Choice_Point", которая позволяет ей создавать дополнительные значения на отступлении.

Ответ 1

bet(N, M, K) :- N =< M, K = N.
bet(N, M, K) :- N < M, N1 is N+1, bet(N1, M, K).

В действии:

$ swipl
?- [bet].
% bet compiled 0.00 sec, 1,064 bytes
true.

?- bet(1,5, K).
K = 1 n
K = 2 n
K = 3 n
K = 4 n
K = 5 n
false.

Если вы используете разрез, вы можете предотвратить окончательный поиск и восстановить точное встроенное поведение /3:

bet(N, M, K) :- N < M, K = N.
bet(N, M, K) :- N == M, !, K = N.
bet(N, M, K) :- N < M, N1 is N+1, bet(N1, M, K).

В действии:

?- [bet].
% bet compiled 0.00 sec, 416 bytes
true.

?- between(1,5,K).
K = 1 n
K = 2 n
K = 3 n
K = 4 n
K = 5.

?- [bet].
% bet compiled 0.00 sec, 240 bytes
true.

?- bet(1,5,K).
K = 1 n
K = 2 n
K = 3 n
K = 4 n
K = 5.

Ответ 2

То, что вы действительно спрашиваете, - как создать точку выбора. Вы получаете решение, когда у вас есть успешное объединение. Что происходит в первом предикате @seanmcl:

bet(N, M, K) :- N =< M, K = N.

Чтобы получить точку выбора, вам нужно иметь альтернативы. Есть только два способа получить альтернативу в Prolog: с явным "или": ; или путем подачи другого правила. Код @seanmcl дает другое правило, которое идиоматично для этой ситуации.

Чтобы дать еще один пример, member/2 создает решение для каждого элемента в списке, но нет никакой магической функции C, всего два правила:

member(X, [X|_]).
member(X, [_|Xs]) :- member(X, Xs).

Посмотрим, что здесь происходит с member(X, [1,2]). Во-первых, используется первое правило и [X|_] объединяется с [1,2], создавая X=1, _=[2]. Это успешное объединение, поэтому создается решение. Если это не сработает (например, нажав ; на консоли), начнется обратное отслеживание. Следующая точка выбора находится между двумя правилами, поэтому вводится следующее правило. [_|Xs] объединяется с [1,2], создавая привязку Xs=[2], а затем вызывается member(X, [2]). При повторном входе те же решения могут быть сделаны снова, поэтому применяется первое правило member(X, [X|_]) и производится привязка X=2. Это решение. Если вы снова вернетесь, вы получите безобидный отказ, потому что ни одно из правил не объединяется с [].

Я надеюсь, что это немного облегчит ситуацию.