Ошибка "Free variable in expression" в Про́логe появляется, когда вы пытаетесь выполнить арифметическую операцию или сравнение над переменной, которая ещё не связана (неinstantiated). Типичные примеры: использовать is/2, =:=, >, < и т.п. до того, как операнды будут известны.
Что нужно сделать — два варианта:
1) Исправить порядок целей / добавить проверки, чтобы арифметические операции выполнялись только тогда, когда переменные связаны.
- Например, вместо
X is Y + 1, …
нужно гарантировать, что Y уже привязан: …, Y = 5, X is Y + 1.
- Или явно проверить nonvar(Y) перед вычислением:
nonvar(Y), X is Y + 1, …
2) Если вы хотите работать с не связными переменными (решать уравнения, генерировать решения), используйте библиотеку ограничений по целым (CLP(FD)) и операторы #=, #\=, #<, #> и т.д. Они допускают неопределённые переменные и ставят на них ограничения:
:- use_module(library(clpfd)).
рядом(R,C,R1,C1) :-
(R1 #= R, C1 #= C+1) ;
(R1 #= R, C1 #= C-1) ;
(R1 #= R+1,C1 #= C) ;
(R1 #= R-1,C1 #= C).
Пример конкретной ошибки и её исправления. Частая ситуация: вы добавили правило рядом/… и теперь предикат занято/… вызывает арифметику с незвязанной переменной:
Неправильно:
занято(R,C) :- рядом(R,C,R2,C2), поле(R2,C2,1), ….
рядом(R,C,R2,C2) :- R2 is R, C2 is C+1 ; … % вызовет ошибку если R,C не заданы
Правильно (гарантируя связывание перед is) — либо вызывать рядом только когда R,C известны, либо использовать CLP(FD):
:- use_module(library(clpfd)).
рядом(R,C,R2,C2) :-
(R2 #= R, C2 #= C+1) ;
(R2 #= R, C2 #= C-1) ;
(R2 #= R+1, C2 #= C) ;
(R2 #= R-1, C2 #= C).
Советы для отладки
- Посмотрите трассировку (trace) и определите, где именно стоит незвязанная переменная. Сообщение вида pos: 822,707 подсказывает позицию в файле.
- Используйте var/1 и nonvar/1 для диагностики и защиты.
- Не пытайтесь вычислять X is Expr, когда Expr содержит свободные переменные.
Если хотите, пришлите фрагменты ваших правил рядом/… и занято/…, я покажу точную правку.