Я не согласен с @ssBarBee. В конце концов, вы должны получить 4321, если вы предоставите свой список и их утверждение верно; но вместо этого вы получаете это:
?- my_digits(Num, [1,2,3,4]).
ERROR: is/2: Arguments are not sufficiently instantiated
Мы могли бы попробовать это с clpfd
:
my_digits( 0, [] ).
my_digits(N,[A|As]) :- N1 #= N/10, A #= N mod 10, my_digits(N1, As).
Мы получаем это:
?- my_digits(Num, [1,2,3,4]), label([Num]).
Num = -6789 ;
Num = 4321.
Я нахожу все это довольно любопытным, но трассировка с помощью clpfd не доставляет удовольствия.
Если бы вы просто хотели проанализировать список чисел, я был бы склонен сделать его хвостовым рекурсивным, например:
my_digits(Num, List) :- my_digits(0, List, Num).
my_digits(Num, [], Num).
my_digits(N, [A|As], Num) :- N1 is N * 10 + A, my_digits(N1, As, Num).
Это дает нам:
?- my_digits(Num, [1,2,3,4]).
Num = 1234 ;
false.
Но он не генерирует:
?- my_digits(1234, X).
ERROR: is/2: Arguments are not sufficiently instantiated
Если бы я решал это без clpfd, я был бы склонен просто проверять свои аргументы и иметь отдельные предикаты. Жестоко, я знаю, но я бы так поступил.
my_digits(Num, List) :-
nonvar(List),
my_digits_p(0, List, Num).
my_digits(Num, List) :-
var(List),
my_digits_g(Num, ListRev),
reverse(ListRev, List).
my_digits_p(Num, [], Num).
my_digits_p(N, [A|As], Num) :- N1 is N * 10 + A, my_digits(N1, As, Num).
my_digits_g(0, []) :- !.
my_digits_g(N, [A|As]) :- A is N mod 10, N1 is floor(N / 10), my_digits_g(N1, As).
Это может анализировать или проверять или генерировать, если число не является переменной:
?- my_digits(1234, X).
X = [1, 2, 3, 4].
?- my_digits(X, [1,2,3,4]).
X = 1234 ;
false.
?- my_digits(1234, [1,2,3,4]).
true;
false.
Если вы попытаетесь сгенерировать оба аргумента в качестве переменных, вы получите довольно бесполезный результат:
?- my_digits(X, Y).
X = 0,
Y = [].
Итак, мы можем попытаться сгенерировать, добавив еще один особый случай в my_digits:
my_digits(Num, List) :-
var(Num), var(List),
my_digits_g_from(0, Num, ListRev),
reverse(ListRev, List).
my_digits(Num, List) :-
nonvar(List),
my_digits_p(0, List, Num).
my_digits(Num, List) :-
var(List),
my_digits_g(Num, ListRev),
reverse(ListRev, List).
my_digits_g_from(N, N, List) :- my_digits_g(N, List).
my_digits_g_from(N, Num, List) :- succ(N, N1), my_digits_g_from(N1, Num, List).
Это большой объем кода и хорошая демонстрация акробатических трюков, которые приходится выполнять, когда не используется clp(fd)
. К сожалению, при выполнении арифметических операций на Прологе приходится обходить тот факт, что is
не унифицирует, но сложность clp(fd)
является хорошим доказательством того, почему это так.
Я надеюсь, что у кого-то есть более элегантное решение!
person
Daniel Lyons
schedule
17.04.2013