Можете ли вы написать между 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
. Это решение. Если вы снова вернетесь, вы получите безобидный отказ, потому что ни одно из правил не объединяется с []
.
Я надеюсь, что это немного облегчит ситуацию.