Более безопасные тесты типа в Prolog

ISO-Prolog (ISO / IEC 13211-1: 1995, включая Cor.1: 2007, Cor.2: 2012) предлагает следующие встроенные предикаты для тестирования типа термина:

8.3 Типовое тестирование

1 var / 1. 2 атома / 1. 3 целое число / 1. 4 float / 1. 5 атомных / 1. 6 соединение / 1. 7 nonvar / 1. 8 номер / 1. 9 вызываемых / 1. 10 земля / 1. 11 acyclic_term / 1.

Внутри этой группы есть те, чья цель состоит исключительно в том, чтобы протестировать определенный экземпляр, то есть 8.3.1 var/1 , 8.3.7 nonvar/1 , 8.3.10 ground/1 , и те, которые предполагают, что термин достаточно инстанцирован так что тест типа безопасен. К сожалению, они сочетаются с тестированием для конкретного экземпляра.

Рассмотрим integer(X) цели integer(X) которое терпит неудачу, если X – невариантный член, который не является целым числом, а X – переменной. Это разрушает многие желательные декларативные свойства:

 ?- X = 1, integer(X). true. ?- integer(X), X = 1. false. 

В идеале второй запрос либо преуспеет, используя некоторую форму сопроводительной обработки; или он выдаст ошибку создания экземпляра 1 в соответствии с classификацией ошибок . В конце концов:

7.12.2 Классификация ошибок

Ошибки classифицируются в соответствии с формой Error_term:

a) При возникновении ошибки при создании
аргумент или один из его компонентов является переменной, а
требуется экземпляр аргумента или компонента. В нем есть
формы instantiation_error .

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

Быстрое исправление этой ситуации заключалось бы в том, чтобы добавить явный тест перед каждым встроенным тестированием, либо дословно, как

  ( var(T) -> throw(error(instantiation_error,_)) ; true), integer(T), .... 

или более компактно, как

 functor(T, _,_), integer(T), .... 

это может быть даже

 T =.. _, integer(T), ... 

Мой вопрос двоякий:

Как обеспечить эту функциональность на уровне пользователя?

и, чтобы сделать это также немного сложным:

Какова самая компактная реализация более безопасного atomic/1 записанного в ISO-Prolog?


1 Другими менее желательными параметрами могут быть петли или создать ошибку ресурса. Еще предпочтительнее неправильного результата.

    Это очень наивная попытка реализовать оба предлагаемых вами решения.

    Во-первых, has_type(Type, Var) который преуспевает или сбой при ошибке создания:

     has_type(Type, X) :- var(X), !, throw(error(instantiation_error, _)). has_type(Type, X) :- nonvar_has_type(Type, X). nonvar_has_type(atom, X) :- atom(X). nonvar_has_type(integer, X) :- integer(X). nonvar_has_type(compound, X) :- compound(X). % etc 

    Во-вторых, could_be(Type, Var) (аналог to must_be/2 ), который использует сопроцессор, чтобы позволить запросу добиться успеха в какой-то момент в будущем:

     could_be(Type, X) :- var(X), !, freeze_type(Type, X). could_be(Type, X) :- nonvar_has_type(Type, X). freeze_type(integer, X) :- freeze(X, integer(X)). freeze_type(atom, X) :- freeze(X, atom(X)). freeze_type(compound, X) :- freeze(X, compound(X)). % etc 

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

    EDIT: «Типы» в Prolog

    Типы в Prolog, как я их понимаю, не являются «типами»: это просто информация, которую можно запросить во время выполнения, и которая существует, потому что она является полезной негерметичной абстракцией базовой реализации.

    Единственным способом, которым я смог практично использовать «тип», было «пометить» мои переменные, как в составных терминах number(1) , number(pi) , operator(+) , date(2015, 1, 8) и т. Д. Затем я могу помещать переменные в них, писать детерминированные или полудетерминированные предикаты, понимать, что мой код означает, когда я вижу это через неделю.

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

    Очень вероятно, что здесь я смешиваю очень разные вопросы; и, честно говоря, мой опыт работы с Prolog в лучшем случае ограничен. Я просто прочитал документацию по реализации, которую я использую, и попытаюсь найти лучший способ использовать ее в моих интересах.

    Тестирование на типы должно отличать себя от традиционных встроенных модhive тестирования типа, которые неявно также проверяют на достаточный экземпляр. Поэтому мы эффективно тестируем только для экземпляра типа ( itype ). И если они недостаточно созданы, возникает соответствующая ошибка. Для типа nn существует, таким образом, предикат тестирования nn_itype/1 с единственным условием ошибки

    a) Если существует θ и σ такое, что nn_itype(Xθ) истинно, а nn_itype(Xσ) ложно
    instantiation_error .

     atom_itype(A) :- functor(A, _, _), % for the instantiation error atom(A). integer_itype(I) :- functor(I, _, _), integer(I). atomic_itype(AC) :- functor(AC,_,0). list_itype(L) :- \+ \+ length(L, _), % for silent failure sort(L, _). % for the instantiation error 

    В SWI, из-за его различного поведения по length/2 , используйте скорее:

     list_itype(L) :- '$skip_list'(_, L, T), functor(T,_,_), T == []. 
    Interesting Posts

    Извлечение файлов из поля Attachment в базе данных Access

    Почему эти уравнения деления приводят к нулю?

    Как я могу использовать средство просмотра событий для подтверждения времени входа в систему, отфильтрованного пользователем?

    Как подписать уже собранный Apk

    Генерация случайных массивов без дубликатов

    Как определить, какой HD участвует в средстве просмотра событий?

    В чем разница между логическим и условным И, ИЛИ в C #?

    Являются ли «C: \ ProgramData» и «C: \ Users \ All Users» одинаковыми? Мне нужны оба?

    Отредактируйте файл реестра Windows, system.dat

    На Ubuntu, почему «sudo apt-get» иногда и «sudo aptitude» в других случаях?

    Минимальный и правильный способ сопоставления «один ко многим» с NHibernate

    Как преобразовать формат даты в DD-MM-YYYY в C #

    Что такое облачные вычисления?

    Панель задач Windows 7: как унифицировать только некоторые значки?

    Как изменить FontSize в Android WebView?

    Давайте будем гением компьютера.