Проверить, является ли переменная пустой или заполненной

У меня есть следующая проблема:

программа пролога:

man(thomas, 2010).
man(leon, 2011).
man(thomas, 2012).
man(Man) :- once(man(Man, _).

проблема:

?- man(thomas).
true ;        %i want only on true even if there are more "thomas" *working because of once()*

?- man(X).
X = thomas ;  %i want all man to be listed *isn't working*

цель:

?- man(thomas).
true ;

?- man(X).
X = thomas ;
X = leon ;
X = thomas ;

Я понимаю, почему это происходит, но все же хочу получить имена всех людей. Итак, мое решение будет заключаться в том, чтобы посмотреть, инициализирован ли «Человек», если да, то «один раз..», иначе... что-то вроде этого:

man(Man) :- (->check<-,once(man(Man, _)); man(Man, _).

При «проверке» должен быть снят код, который проверяет, заполнена ли переменная «Человек».

Это возможно?


person Spenhouet    schedule 05.01.2014    source источник
comment
С вашим существующим кодом я не получаю сообщение об ошибке при вводе man(X). Я получаю X = thomas. И если я ввожу man(_), я получаю true. Если вы хотите проверить, был ли уже создан экземпляр переменной, вы можете использовать var(Man) (true означает отсутствие экземпляра).   -  person lurker    schedule 06.01.2014
comment
Год, правильно, я ошибся, но в X и _ я не хочу, чтобы все мужчины были перечислены. Это не так. Похоже, var(Man) — это то, что мне нужно. Но m(Mann) :- ((not(var(Mann))), раз(m(Mann, _))); м(Манн, _). всегда выбирает m(Mann, _).   -  person Spenhouet    schedule 06.01.2014
comment
Вы не можете получить результаты в анонимной переменной, такой как _. Он будет отвечать только true или false, так как он анонимен! Вам нужно X или что-то в этом роде. Что касается ваших предикатов, пожалуйста, обновите (отредактируйте) описание проблемы, указав дополнительную информацию для ясности. :)   -  person lurker    schedule 06.01.2014
comment
Я попробовал обновить ваш код, и он работает точно так, как запрограммировано. Если Mann не конкретизирован, он выбирает m(Mann, _), потому что это то, что говорит логика. И если создается экземпляр Mann (например, вы вводите man(thomas)., то выбирается once(m(Mann,_)). Я не уверен, что понимаю, какую логику вы хотите установить.   -  person lurker    schedule 06.01.2014
comment
Я запутался. В своем последнем комментарии вы говорите именно то, что я хочу установить. :) но этот код, который я разместил в комментарии, у меня не работает. man(thomas). дает мне истинное 3 раза. :/   -  person Spenhouet    schedule 06.01.2014
comment
В своем посте я добавил это решение и результат 1: 1. В чем разница с вашим кодом?   -  person Spenhouet    schedule 06.01.2014
comment
Я не говорил, что man(thomas) дал только один true, а только то, что он дал true. У него есть несколько решений, потому что (а) есть два элемента базы данных, которые имеют thomas, поэтому он находит оба, и (б) он снова будет успешным благодаря вашему или пункту ;.   -  person lurker    schedule 06.01.2014
comment
Это проблема, почему я делаю это один раз. Мне нужна только одна истина, когда Томас - мужчина man(thomas)., но человек (X) и мужчина (_) должны работать нормально.   -  person Spenhouet    schedule 06.01.2014
comment
Год хороший. Я также попробовал это секунду назад, и это работает :) Пожалуйста. опубликуйте это как решение, чтобы я мог отдать вам должное за вашу помощь и время :)   -  person Spenhouet    schedule 06.01.2014
comment
Прохладный. Извините, что я был таким глупым - мне потребовалось некоторое время, чтобы понять, чего вы хотите достичь.   -  person lurker    schedule 06.01.2014
comment
Извините, что я не мог сделать это ясно. Но большое спасибо. Вы мне очень помогли. пс. Я только что обнаружил, что вместо not(var()) есть nonvar(). Лишь бы улучшить.   -  person Spenhouet    schedule 06.01.2014
comment
Да, я забыл про nonvar. Хороший улов. :)   -  person lurker    schedule 06.01.2014
comment
Твое право. Once() также больше не нужен. :) Теперь я очень доволен этим прекрасным решением и могу идти спать^^ Сейчас 00:44.   -  person Spenhouet    schedule 06.01.2014


Ответы (2)


Один из способов добиться этого заключается в следующем:

man(X) :-
    (nonvar(X), man(X, _)), !
    ;
    man(X, _).

Или, что более предпочтительно, было бы:

man(X) :-
    (   var(X)
    ->  man(X, _)
    ;   once(man(X, _))
    ).

Разрез обеспечит только одно решение (максимум) для экземпляра X, тогда как случай без экземпляра будет идти своим чередом. Обратите внимание, что с разрезом вам не нужно once/1. Причина, по которой once/1 не работает должным образом без разреза, заключается в том, что поиск с возвратом все равно вернется, примет условие "или" и преуспеет и там.

person lurker    schedule 05.01.2014
comment
Спасибо! Это идеально :) - person Spenhouet; 06.01.2014
comment
Спасибо @false - в этом случае once/1 (по крайней мере, так, как это пытался сделать OP) позволил вернуться, чтобы найти одно имя, такое как thomas, несколько раз при запросе как man(thomas), чего OP пытался избежать. Однако я, возможно, не выразил это должным образом, чтобы заставить его работать так, как хотелось бы. Я думаю, что решение setof, которое у вас есть, работает лучше всего, если предположить, что ОП не хочет избыточных решений, как следует из их вопроса. - person lurker; 06.01.2014
comment
@false о, отличный улов. Я даже не думал об этом после того, как изменил поток, который намного лучше (отредактированный). - person lurker; 06.01.2014
comment
@lurker У меня есть планировщик экзаменов в прологе. Если это экземпляр X, мне сначала нужно отсортировать X (список). После этого я могу проверить, действителен ли список (или не конкретизирован - сгенерировать расписание). Но я проверил с помощью функции count_proofs, и когда я добавляю эту проверку, она дает мне 317952 результата. Без проверки (только генерация) это дает мне 9936 результатов. Почему эта проверка дает мне больше результатов? - person Ken Vernaillen; 25.12.2015
comment
@KenVernaillen, почему бы вам не опубликовать вопрос о переполнении стека, показывающий соответствующий код? Не видя кода, сложно ответить на ваш вопрос. - person lurker; 26.12.2015

man(X) :-
   setof(t,Y^man(X,Y),_).

В дополнение к тому, что вы спрашиваете, это удаляет избыточные ответы/решения.

Встроенная функция setof/3 в своем последнем аргументе описывает отсортированный список решений, найденных в первом аргументе. И это для каждого отдельного экземпляра свободных переменных цели. Свободные переменные — это те, которые не встречаются ни в первом аргументе, ни в качестве экзистенциальной переменной в термине слева от (^)/2.

В нашем случае это означает, что последним аргументом всегда будет [t], что неинтересно. Поэтому _.

В цели входят две переменные: X и Y. Или, если быть более точным, переменные, содержащиеся в X и Y. Y — это экзистенциальная переменная.

Единственная свободная переменная — X. Таким образом, все решения для X перечислены без дублирования. Обратите внимание, что вы не можете зависеть от точного порядка сортировки в этом конкретном случае во многих реализациях.

person false    schedule 06.01.2014
comment
Работает нормально (имена тоже отсортированы). Но я должен признать, что я не понимаю, как это работает. Почему t и что делает Y^? Я знаю, что setof ищет что-то (t) в списке (_), созданном из (Y^man(X,Y)), или? - person Spenhouet; 06.01.2014
comment
Спасибо. Это было полезно :) - person Spenhouet; 06.01.2014