Сначала рассмотрит использование более содержательное соглашения об именовании: Я рекомендую присоединени «с» к именам переменных, которые обозначают списки, и нумерацию их более систематически (начиная с 0), и используя более декларативный и значимое имя предиката:
with_distinct_integers(E0, E) :-
term_variables(E0, Vs),
with_distinct_integers(E0, Vs, [0,1,2,3,4,5,6,7,8,9], E).
with_distinct_integers(E, [], [], E).
with_distinct_integers(E, [], _, E).
with_distinct_integers(E0, Vs0, Ns0, E) :-
select(Num, Ns0, Ns),
select(Var, Vs0, Vs),
Var is Num,
with_distinct_integers(E0, Vs, Ns, E).
Сосредоточение на with_distinct_integers/4
Сейчас. Вы видите, что первое предложение добавляется вторым, поэтому вы можете опустить первое предложение без потери решений. Переменная Var
только используется, чтобы объединить его с Num
, так что вы можете использовать одну переменную сразу:
with_distinct_integers(E, [], _, E).
with_distinct_integers(E0, Vs0, Ns0, E) :-
select(Num, Ns0, Ns),
select(Num, Vs0, Vs),
with_distinct_integers(E0, Vs, Ns, E).
Вы все еще найти непреднамеренные дублирующие решения этой упрощенной версии, и я оставляю его в качестве легкого упражнения, чтобы найти вне зависимости от причины:
?- with_distinct_integers(X-Y, [X,Y], [0,1], A).
..., A = 0-1 ;
..., A = 1-0 ;
..., A = 1-0 ;
..., A = 0-1 ;
false.
Подсказка: просто рассудительно по упрощенному определению. Продолжая упрощение: зачем проходить первоначальный термин, когда у вас уже есть все, что вам нужно, т. Е. Его переменные, доступные? Рассмотрим:
with_distinct_integers(E) :-
term_variables(E, Vs),
numlist(0, 9, Ns),
with_distinct_integers(Vs, Ns).
with_distinct_integers([], _).
with_distinct_integers([V|Vs], Ns0) :-
select(V, Ns0, Ns),
with_distinct_integers(Vs, Ns).
Пример запроса, считая все решения:
?- findall(., with_distinct_integers([X-Y]), Ls), length(Ls, L).
Ls = ['.', '.', '.', '.', '.', '.', '.', '.', '.'|...],
L = 90.
сюрприз на стороне: есть только 90 решений, а не 99.
Также рекомендуется использовать конечные ограничения домена, которые являются отношения над целыми числами, которые позволяют легко сформулировать такие задачи:
:- use_module(library(clpfd)).
with_distinct_integers(E) :-
term_variables(E, Vs),
Vs ins 0..9,
all_different(Vs),
label(Vs).
Пример запроса:
?- with_distinct_integers(X-Y).
X = 0,
Y = 1 ;
X = 0,
Y = 2 ;
X = 0,
Y = 3 .
Отличный anwser, спасибо за объяснения, не используя cplfd. – vvondra