Я использую интерпретатор Prolog в OCaml. Проблема, с которой я столкнулся, заключается в основной функции. Я по существу стараюсь хранить стек интерпретатора в вызове функции и модифицировать копию этого стека, которая затем передается в рекурсивный вызов из этого конкретного вызова функции. Когда этот рекурсивный вызов сообщает об ошибке, этот оригинальный вызов функции должен использовать исходный стек, который я сохранил без изменений, и сделать другой рекурсивный вызов (для реализации обратного отслеживания).Стек автоматически изменяется, когда он не должен
Теперь вот в чем проблема. Стек и временный стек (tempstack) оба изменяются, когда я намерен только изменить tempstack. Я потратил часы, пытаясь понять проблему, и я уверен, что это все. Вот основная функция сниппет ..
let rec main stack clauselist counter substitutions variablesinquery answers =
try
let currentsubgoal = Queue.top (Stack.top stack) in
if counter <> List.length clauselist
then
let tempstack = Stack.copy stack in
try
let unifier = mgu1 currentsubgoal (List.nth clauselist counter) in
let newsubgoals =
match List.nth clauselist counter with
Fact(a) -> []
| Rule(Headbody(a,b)) -> b
in
let tempstack = stacknewsubgoals tempstack unifier newsubgoals in
let tempsubs = match substitutions with
S(m) -> match unifier with S(n) -> S(m @ n) in
try
main tempstack clauselist 0 tempsubs variablesinquery answers
with BackTrack -> main stack clauselist (counter + 1) substitutions
variablesinquery answers
with NoUnifier -> main stack clauselist (counter + 1) substitutions
variablesinquery answers
else raise BackTrack
with Queue.Empty ->
let answers = buildanswer substitutions variablesinquery :: answers in
raise BackTrack
Единственное вычисление, которое происходит на tempstack, что новые цели были вставлены в нее с помощью другой функции (stacknewsubgoals) (Примечание: стек стек очередей).
Я попытался заменить временную стопку во внутреннем стеке try для стека (где выполняется основной рекурсивный вызов). Вместо того, чтобы переходить в бесконечный цикл (потому что тот же самый стек должен быть передан без изменений снова и снова), он заканчивается исключением Not_Found, которое, в свою очередь, генерируется моим исключением Queue.Empty внизу. По сути, так или иначе очередь в нижней части стека становится пустой, когда она должна быть определенно не пустой.
let stacknewsubgoals tempstack unifier newsubgoals =
let tempq = Stack.pop tempstack in
let subbedq = substituteinqueue tempq unifier (Queue.create()) in
if (newsubgoals <> []) then
(Stack.push subbedq tempstack;
Stack.push (Queue.create()) tempstack;
initialize (Stack.top tempstack) (substpredicatelist newsubgoals unifier);
tempstack)
else
(Stack.push subbedq tempstack;
ignore (Queue.pop (Stack.top tempstack));
tempstack)
Здесь вы можете ясно видеть, что единственная вещь, которая изменяется этой функцией, - это tempstack. Любая помощь в определении того, почему исходный стек, передаваемый в качестве аргумента в функции, не остается неизменной, будет очень оценена!
Я переформатировал первый блок кода в вашем вопросе, чтобы лучше соответствовать обычным стандартам кодирования ocaml. Мне легче читать (и, возможно, многие другие). Не стесняйтесь откатывать изменения в свою версию, если вам это не нравится. Я также взял на себя смелость устранить лишние парнеры. Надеюсь, вы не возражаете против такой навязчивой модификации вашей первоначальной записи. – didierc