2014-12-09 3 views
18

Рассмотрим (мета-логический) предикат var_in_vars(Var, Vars) который принимает переменную Var и список переменных Vars и преуспевает, если Var происходит в Vars. Поэтому нам не нужно гарантировать, что Var является переменной, или что Vars - это список переменных.Переменная появление в списке переменных

Что является самым компактным и каноническим способом выразить это в ISO Prolog? Вот overview of the built-ins в ISO/IEC 13211-1: 1995, включая Cor.2: 2012.

?- var_in_vars(V, [U,V,W]). 
true. 

?- var_in_vars(V, [X,Y,Z]). 
false. 

ответ

8

Одним из возможных вариантов:

var_in_vars(V, Vs) :- \+ unify_with_occurs_check(V, Vs). 

и короче:

var_in_vars(V, Vs) :- \+ subsumes_term(V, Vs). 

EDIT: Будущие читатели, пожалуйста, примите во внимание контекст вопроса, который представляет собой специфический Компактность вызов включая экспрессивность предикатов ISO при данных обстоятельствах.

В других обстоятельствах, вы, вероятно, больше пользы от определения, как:

var_in_vars(V, Vs) :- 
     must_be(list, Vs), 
     once((member(X, Vs), V == X)). 
+0

Очень приятно, действительно! Но здесь есть одна небольшая проблема (я признаю, что она выходит за рамки стандарта): что, если 'V' привязано к некоторому ограничению или просто« замораживать (V, eeek) », var_in_vars (V, [A, B , C]). ' – false

+0

(Для будущих читателей): вторая принята. ['subsumes_term/2'] (http://www.complang.tuwien.ac.at/ulrich/iso-prolog/dtc2#subsumes_term) - это чистый тестовый предикат, без унификаций, где' unify_with_occurs_check/2' фактически объединяет переменная. – false

7

Это определение проходит испытания, но ... я пропустил некоторые тонкости?

var_in_vars(V, [H|_]) :- V == H, !. 
var_in_vars(V, [_|T]) :- var_in_vars(V, T). 
+1

Это, безусловно, хорошее решение. Определенно не самый компактный или канонический. – false

+2

Очень хорошая первая попытка! Требуется мужество для участия -> +1! – mat

+0

@mat: спасибо! это был определенно дух, который я решил опубликовать таким наивным ответом. Поскольку я прочитал четкие подсказки в вопросах («нам не нужно гарантировать, что Var является переменной, или что Vars - это список переменных»), которые явно указывают, что сканирование списка не требуется, я потерял просмотр документов ... Ваш ответ очень поучителен – CapelliC

5

И здесь идет еще один, хотя немного сложнее:

var_in_vars(V, Vs) :- 
    term_variables(Vs+V, Ws), 
    Ws == Vs. 

Так это полагается на точный как перемещаются переменные. И так как это well defined в стандарте мы можем рассчитывать, что они

... появляются в соответствии с их первого появления в левой направо обходе ...

Недостатком этого определения является что он имеет минимальную стоимость, пропорциональную длине Vs. Но поскольку внутренний обход часто довольно эффективно реализуется, это не такая проблема.

У него есть одно большое преимущество: оно преуспевает только в том случае, если Vs - это список переменных.

0

Решение Синтез

Решение: Short

var_in_vars(V, Vs) :- \+ subsumes_term(V, Vs). 

Альтернатива 1: Простой

var_in_vars(V, Vs) :- \+ unify_with_occurs_check(V, Vs). 

Вариант 2: В зависимости от обстоятельств, это может быть более подходящим

var_in_vars(V, Vs) :- 
     must_be(list, Vs), 
     once((member(X, Vs), V == X)). 

Вариант 3: Более сложные

var_in_vars(V, Vs) :- 
    term_variables(Vs+V, Ws), 
    Ws == Vs. 

Вариант 4: Другая возможность

var_in_vars(V, [H|_]) :- V == H, !. 
var_in_vars(V, [_|T]) :- var_in_vars(V, T). 

Ссылка:

Standard


Примечание: контекст вопроса, который представляет собой специфическая Компактность вызова с участием выразительности ISO предикатов при данных обстоятельствах.

+0

** Все ** код альтернатив 1..4 исходит из других ответов. Что такое ** ваш ** вклад? – repeat

+0

Я новичок в SO, и в соответствии с тем, что сказал «Джоэл Спольский», хорошо сделать ответ, который является полным и понятным, даже если ответ берется у других пользователей, плюс здесь - дать полный ясный синтетический ответ в один единственное место ... я знаю, что это спорный вопрос я согласен. пожалуйста, дайте мне знать, что вы думаете, и укажите мне, если я ошибаюсь. – intika

+3

Не обижайтесь, на самом деле. Я был просто удивлен, когда я просматривал ответ и «соединял точки», чтобы узнать, как вы переварили другие ответы. В этом нет ничего плохого, но это первый для меня как читатель. – repeat

2

Альтернативное решение:

var_in_vars(V, Vs) :- 
    \+ (V = Vs, acyclic_term(Vs)). 

Но решения по @mat лучше и изящнее, и решение по @CapelliC долгое время самым портативным один (subsumes_term/2 предикат был только недавно стандартизированы и не все системы предоставили предикат unify_with_occurs_check/2).

+0

'V = Vs' может быть STO, и поэтому поведение не определено. – false

+0

Да, и одна из причин, почему я не решался опубликовать это решение в течение некоторого времени. Тем не менее, до сих пор единственными системами, в которых я нашел это определение проблематичным, являются системы, которые еще не обеспечивают стандартный предикат 'acyclic_term/1'. –

1

Раствор @false может быть упрощено до:

var_in_vars(V, Vs) :- 
    term_variables(Vs+V, Vs). 

Когда V является членом Vs списка, второй аргумент возвращает Vs (из-за левого направо обхода Vs+V термина) , Когда V не является членом Vs, второй аргумент возвращает список, содержащий еще один элемент, чем Vs и, следовательно, не может объединяться с ним. Хотя во втором аргументе есть неявное объединение, ни в одном случае существует опасность создания циклического термина. То есть унификация, являющаяся СТО, не является проблемой в этом упрощенном решении.

Но есть упрощение it w.r.t. представление? Использование равенства, (==)/2 имеет потенциал неудачи раньше и, таким образом, делает оригинальное решение быстрее.

+0

Это удается, если длина обоих списков имеет одинаковую длину, однако это может привести к неожиданным объединениям в случае, скажем, 'var_in_vars (V, [a])' ​​ – false

+0

. Это вне ** ваших ** установленных условий: «Итак нам не нужно гарантировать, что Var является переменной, или что Vars - это список переменных ». –

+0

Правильно, но чистый тестовый предикат фактически объединяет что-то, тем не менее, что-то довольно неожиданное. Вы можете поместить '\ + \ +' вокруг, но затем он все еще ** будет унифицирован, что может наблюдаться через ограничения. – false

Смежные вопросы