Копировать термин с переменными без привязки переменных
С SWI-Прологом.
Как можно копировать термин с переменными без привязки переменных?
Что я пробовал
Я пробовал copy_term / 2 и duplicate_term / 2
Например:
foo(c).
foo(E) :-
E = bar(a,b,X),
copy_term(E,Ec),
duplicate_term(E,Ed),
write("E: "),write(E),nl,
write("Ec: "),write(Ec),nl,
write("Ed: "),write(Ed),nl.
результаты в
?- foo(bar(a,b,bar(a,b,bar(a,b,c)))).
E: bar(a,b,bar(a,b,bar(a,b,c)))
Ec: bar(a,b,bar(a,b,bar(a,b,c))) <-- Copy
Ed: bar(a,b,bar(a,b,bar(a,b,c))) <-- Duplicate
true.
?- foo(bar(a,b,bar(a,b,c))).
E: bar(a,b,bar(a,b,c))
Ec: bar(a,b,bar(a,b,c)) <-- Copy
Ed: bar(a,b,bar(a,b,c)) <-- Duplicate
true.
?- foo(bar(a,b,c)).
E: bar(a,b,c)
Ec: bar(a,b,c) <-- Copy
Ed: bar(a,b,c) <-- Duplicate
true.
и проверил раздел " Анализ и построение условий"
Что мне нужно
Вот En
результат предиката, возвращающего то, что мне нужно
?- foo(bar(a,b,bar(a,b,bar(a,b,c)))).
E: bar(a,b,bar(a,b,bar(a,b,c)))
En: bar(a,b,X), <-- Need this
true.
?- foo(bar(a,b,bar(a,b,c))).
E: bar(a,b,bar(a,b,c))
En: bar(a,b,X), <-- Need this
true.
?- foo(bar(a,b,c)).
E: bar(a,b,c)
En: bar(a,b,X), <-- Need this
true.
Я надеялся на встроенный предикат.
TL; DR
Необходимость в этом заключается в решении бинарных выражений. Оригинал используется для выбора предиката и для решения выражения. Копия, которую я называю локальной, используется для отображения перезаписи для подвыражения, а копия, которую я называю глобальной, используется для отображения перезаписи, примененной ко всему выражению. Если существует только один термин, например, нет копий, когда переменная связана для одного использования, это приводит к сбою другого использования.
Текущее решение состоит в том, чтобы ввести несколько терминов с разными переменными для каждого использования в предикате. Умножьте это на сотни и, возможно, тысячи предикатов с возможными ошибками ввода или копирования / вставки, и вы увидите необходимость.
Другие соображения
Я также подумал о том, чтобы иметь главную копию термина в предикате, а затем использовать его для создания трех копий. Проблема в том, что одна из копий используется при выборе предиката, поэтому, прежде чем предикат может быть выбран, должна произойти копия. Таким образом, даже если предикат не выбран для оценки, копия должна иметь место в предикате.
foo(c).
foo(Ec) :-
M = bar(a,b,X),
copy_term(M,Ec),
duplicate_term(M,Ed),
write("M: "),write(M),nl,
write("Ec: "),write(Ec),nl,
write("Ed: "),write(Ed),nl.
?- foo(bar(a,b,bar(a,b,bar(a,b,c)))).
M: bar(a,b,_9364)
Ec: bar(a,b,bar(a,b,bar(a,b,c)))
Ed: bar(a,b,_9384)
true.
?- foo(bar(a,b,bar(a,b,c))).
M: bar(a,b,_9240)
Ec: bar(a,b,bar(a,b,c))
Ed: bar(a,b,_9260)
true.
?- foo(bar(a,b,c)).
M: bar(a,b,_9116)
Ec: bar(a,b,c)
Ed: bar(a,b,_9136)
true.
Такcopy_term/2
дает мне копию с привязанными переменными, которая необходима для выбора предиката и оценкиduplicate_term/2
дает мне термин со свободными переменными для использования с другими предикатами.
Пример вывода из реального приложения
Global Local
------------------ -----------------------------
Input (1 + ((0 + 0) + 0))
0 + X -> X (0 + 0) -> 0
= (1 + (0 + 0))
X + 0 -> X (0 + 0) -> 0
= (1 + 0)
X + 0 -> X (1 + 0) -> 1
= 1
1 ответ
(Очень крошечное замечание в начале: скорее используйте одинарные кавычки, а не двойные кавычки для простых атомов.)
В первом случае соответствующей частью является:
foo(E) :-
E = bar(a,b,X),
copy_term(E,Ec),
write('X' = X).
?- foo(bar(a,b,bar(a,b,bar(a,b,c)))).
Вот, E = bar(a,b,X)
уже объединяет X
, который нельзя отменить позже. С $
-дебаггер (см. ниже) получаю:
call:copy_term(bar(a,b,bar(a,b,bar(a,b,c))),A).
exit:copy_term(bar(a,b,bar(a,b,bar(a,b,c))),bar(a,b,bar(a,b,bar(a,b,c))))
Таким образом, основной термин просто копируется.
Во втором случае соответствующей частью является:
foo(Ec) :-
M = bar(a,b,X),
copy_term(M,Ec),
write('Ec: '),write(Ec),nl.
?- foo(bar(a,b,bar(a,b,bar(a,b,c)))).
Сначала обратите внимание на переменные! Ec
это в начале наземный термин. И это не изменится! Неважно, что ты делаешь.
То, что вы на самом деле делаете, это копирование неосновного термина в наземный термин. Теперь, буквально это означает, что вы копируете термин, и копия объединяется с основными терминами. Объединение не может разрушить основательность.
В этом фрагменте вы недовольны тем, что скопированный термин является наземным. На самом деле, до copy_term(M, Ec)
, семестр Ec
уже заточен. Если вы использовали d-bugger и не нашли ошибку, рассмотрите более простую версию и просто добавьте $
перед copy_term/2
, То есть:
foo(Ec) :-
M = bar(a,b,X),
$copy_term(M,Ec),
write('Ec: '),write(Ec),nl.
который производит:
call:copy_term(bar(a,b,A),bar(a,b,bar(a,b,bar(a,b,c)))).
exit:copy_term(bar(a,b,A),bar(a,b,bar(a,b,bar(a,b,c)))).
Ec: bar(a,b,bar(a,b,bar(a,b,c)))
Итак copy_term/2
полностью излишним в этом случае.
Несколько незначительных замечаний: в SWI разница междуcopy_term/2
а также duplicate_term/2
имеет значение только тогда, когда вы делаете деструктивное обновление терминов (не!). Особенно проблематично то, что оба ограничения копирования как-то:
?- X #> Y, copy_term(X,C).
Y#=<X+ -1,
_3398#=<C+ -1,
_3398#=<C+ -1.
?- X #> Y, duplicate_term(X,C).
Y#=<X+ -1,
_3780#=<C+ -1.
?- X #> Y, copy_term_nat(X,C). % syntactic version
Y#=<X+ -1.
В общем, поддержание копий ограничений довольно сложно, лучше избегать этого или относиться к нему более широко. SICStus предлагает только чисто синтаксический copy_term/2
, Если вы хотите больше, вам нужно использовать copy_term/3
,