У вас есть две проблемы. Первый реальный заключается в том, что вам нужно использовать is
вместо =
:
H is X-1
Это необходимо для запуска арифметической оценки. Ваша вторая проблема не является реальной проблемой, но говорит о большем недоразумении, которое заключается в том, что H
и NextX
эквивалентны. Поскольку в Prolog есть только привязки, а не "назначаемые", как это было раньше, вам никогда не понадобится создавать две "переменные" с одной и той же привязкой. Нет состояния, которое вы могли бы изменить позже.
Очистив оба, вы получите следующее:
decListRange(1, []) :- !.
decListRange(X, [H|Rest]) :-
X > 1,
H is X-1,
decListRange(H, Rest).
Изменить 2: реализация clpfd
:- use_module(library(clpfd)).
declist(N, L) :- N == 1, !, L = []. % green cut
declist(1, []).
declist(N, [N1|Ns]) :-
N #> 1,
N1 #= N - 1,
declist(N1, Ns).
У этого есть свойства, которые @false упоминает ниже в комментариях:
?- declist(3, L).
L = [2, 1] ;
false.
?- declist(3, [2,1]).
true ;
false.
?- declist(N, [3,2,1]).
N = 4.
?- declist(N, X).
N = 1,
X = [] ;
N = 2,
X = [1] ;
N = 3,
X = [2, 1] ;
N = 4,
X = [3, 2, 1] ;
N = 5,
X = [4, 3, 2, 1] .
Правка: короткая интермедия о разнице между =
и is
.
В процедурных языках =
почти всегда является синтаксисом для присвоения определенного значения переменной. В Прологе переменные являются привязками, и однажды установленные, они не могут быть изменены напрямую путем переназначения переменной другого значения. Вместо этого они работают больше как переменные в математике и логике, где переменная «заменяет» интересные значения, но сами эти значения в основном неизменяемы. В Прологе =
по существу просит механизм унификации установить привязки. Итак, если бы вы сделали что-то вроде этого:
?- name(X, Y) = name(bob, tony).
Пролог отвечает связыванием переменных:
X = bob,
Y = tony.
Как только эти привязки существуют, противоречащие привязки потерпят неудачу, а утвердительные привязки будут успешными:
?- name(X, Y) = name(bob, tony), X = bob.
X = bob,
Y = tony.
?- name(X, Y) = name(bob, tony), X = william.
false.
Сам алгоритм объединения ничего не знает об арифметике. У этого есть приятный побочный эффект: вы можете использовать любое выражение в чистом виде. Например:
?- Expr = X + 3, Z + Q = Expr.
Expr = Z+3,
X = Z,
Q = 3.
Это, наверное, действительно удивительно выглядит. Вы можете ожидать, что Пролог каким-то образом был достаточно умен, чтобы сохранить выражение, потому что он заметил, что X является переменной или чем-то в этом роде, но это тоже неверно:
?- X = 4, Expr = X + 3, Z + Q = Expr.
X = 4,
Expr = 4+3,
Z = 4,
Q = 3.
Другой взгляд на это состоит в том, что Пролог считает +
просто еще одним оператором, поэтому X+3
— это такой же факт, как и add(X, 3)
, который не обязательно имеет какое-то особое значение. Как бы вы ни смотрели на это, оператор is/2
существует для применения арифметических рассуждений и получения значения:
?- X = 4, Expr is X + 3.
X = 4,
Expr = 7.
Обратите внимание, что Expr имеет вычисленное значение, но не исходную структуру:
?- X = 4, Expr is X + 3, Z + Q = Expr.
false.
На практике, если вам нужно много рассуждать с помощью арифметики, вы захотите использовать библиотеку типа clpfd
или clpqr
в зависимости от того, интересуетесь ли вы целыми числами или вещественными числами. Эта библиотека позволяет вам проще делать более интересные вещи, например указывать, что уравнение выполняется для значений в определенном диапазоне, и получать эти значения.
person
Daniel Lyons
schedule
17.01.2013