2016-02-04 2 views
0

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

ontology.pl:

isSite(Url) :- string(Url). 
guestPostPublished(GuestPostId, Date, Site, Url) :- 
string(GuestPostId), 
date(Date), 
isSite(Site), 
string(Url), 
\+(guestPostPublished(GuestPostId, _, _, _)). 

invalidFile.pl:

isSite('somesite.com'). 
guestPostPublished(
    'gp1', 
    date(2016,2,2), 
    'somesite.com', 
    'someUrl'). 

guestPostPublished(
    'gp1', 
    date(2016,2,2), 
    'somesite.com', 
    'anotherUrl'). 

invalidFile.pl является недействительным, поскольку он нарушает правила, указанные в ontology.pl что все GuestPostId s должны быть уникальными.

Когда я загружаю эти данные в свой движок, я исключаю исключение, указывающее, что данные недействительны. Но это не так.

Что я делаю неправильно? Как я могу убедиться, что когда я подаю неверные данные в TuProlog, я получаю уведомление о некотором роде (например, исключение или какой-то флаг)?

Вот соответствующий фрагмент моего кода (вы можете найти весь код here):

@Test 
public void test2() throws InvalidObjectIdException, IOException, 
     MalformedGoalException, InvalidTheoryException, UnknownVarException, NoSolutionException, 
     NoMoreSolutionException, InvalidLibraryException { 
    final Prolog engine = createEngine(); 

    try 
    { 
     loadPrologFiles(engine, new String[]{ 
       "src/main/resources/ontology.pl", 
       "src/main/resources/invalidFile.pl" 
     }); 
     Assert.fail("Engine swallows invalid Prolog file."); 
    } 
    catch (final Exception exception) { 
     // TODO: Check that the right exception is thrown 
    } 
    final List<String> result = getResults(engine, "guestPostPublished(_,X,_,_).", "X"); 
    System.out.println("result: " + result); 
} 

private Prolog createEngine() throws InvalidObjectIdException { 
    final Prolog engine = new Prolog(); 
    engine.addOutputListener(new OutputListener() { 
     public void onOutput(OutputEvent outputEvent) { 
      System.out.println(String.format("PROLOG: %s", outputEvent.getMsg())); 
     } 
    }); 
    Library lib = engine.getLibrary("alice.tuprolog.lib.OOLibrary"); 
    ((OOLibrary)lib).register(new Struct("stdout"), System.out); 
    return engine; 
} 

private void loadPrologFiles(final Prolog engine, final String[] files) throws IOException, InvalidTheoryException { 
    final List<String> paths = Arrays.asList(files); 
    final StringBuilder theoryBuilder = new StringBuilder(); 

    for (final String path : paths) { 
     theoryBuilder.append(System.lineSeparator()); 
     theoryBuilder.append("% "); 
     theoryBuilder.append(path); 
     theoryBuilder.append(" (START)"); 
     theoryBuilder.append(System.lineSeparator()); 
     theoryBuilder.append(FileUtils.readFileToString(new File(path))); 
     theoryBuilder.append(System.lineSeparator()); 
     theoryBuilder.append("% "); 
     theoryBuilder.append(path); 
     theoryBuilder.append(" (END)"); 
     theoryBuilder.append(System.lineSeparator()); 
    } 

    final Theory test1 = new Theory(theoryBuilder.toString()); 
    engine.setTheory(test1); 
} 

private List<String> getResults(final Prolog engine, final String query, final String varName) throws 
     MalformedGoalException, NoSolutionException, UnknownVarException, NoMoreSolutionException { 
    SolveInfo res2 = engine.solve(query); 

    final List<String> result = new LinkedList<String>(); 
    if (res2.isSuccess()) { 
     result.add(res2.getTerm(varName).toString()); 
     while (engine.hasOpenAlternatives()) { 
      res2 = engine.solveNext(); 
      final Term x2 = res2.getTerm("X"); 
      result.add(x2.toString()); 
     } 
    } 
    return result; 
} 
+1

Обычные прологи не имеют встроенного механизма для ограничений целостности данных так же, как это делает реляционная база данных. Если TuProlog не предлагает это как библиотеку, вы не можете просто объявить первичный ключ. Вы можете реализовать его самостоятельно очень легко, но: есть динамика базы данных? Будет ли это изменяться в течение всей жизни программы? Вам нужно вставить новые строки в эту таблицу? –

+0

@Boris Файлы Prolog не будут меняться во время выполнения. Я хочу, чтобы программа выполняла следующие действия: Прочитайте набор файлов Prolog и сообщите мне, соответствуют ли они правилам, указанным в 'ontology.pl'. Затем программа завершается. –

+0

Кажется, что вы думаете, что делаете с двумя файлами 'ontology.pl' и' invalidFile.pl': один объявляет ограничения целостности данных, а другой содержит все таблицы. Это не так, как это работает. –

ответ

1

Чтобы установить ограничение целостности данных на столе Пролога фактов, вам нужно подойти к этому по-разному. Я бы предложил сначала попробовать сделать это в чистом Prolog без битов Java, просто чтобы понять, что происходит.

Если база данных статическая и не изменяется, ее просто: просто загрузите ее, а затем запустите с ней запросы, которые выполняют проверку целостности данных. Например, у вас есть таблица site/1 с одной колонке, и вы хотите, чтобы убедиться, что все значения являются строками:

Там нет site(S) так что S не является строкой

\+ (site(S), \+ string(S)) 

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

site_must_be_string :- 
    \+ (site(S), \+ string(S)). 

Или, другой, уникальная колонка (первичный ключ):

Там нет дубликатов среди первых аргументов guest_post_published/4

findall(ID, guest_post_published(ID, _, _, _), IDs), 
length(IDs, Len), 
sort(IDs, Sorted), % sort/2 removes duplicates! 
length(Sorted, Len). % length does not change after sorting 

Вы, вероятно, нужны чтобы обернуть это в свой собственный предикат.

1

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

В качестве простого примера, вы можете сделать следующее:

open('invalidFile.pl', read, S), 
read(S, TestFact), 
call(TestFact). 

call(TestFact) будет успешным, если срок читать invalidFile.pl преуспевает учитывая существующие факты и правила, в противном случае она не будет выполнена. Вы можете использовать эту последовательность и прочитать все предполагаемые факты и проверить их:

validate_file(File) :- 
    open(File, read, S), 
    read_terms(S, Terms), 
    maplist(call, Terms), % This will fail if *any* term fails 
    close(S). 

read_terms(Stream, []):- 
    at_end_of_stream(Stream). 

read_terms(Stream, [Term|Terms]):- 
    \+ at_end_of_stream(Stream), 
    read(Stream, Term), 
    read_terms(Stream, Terms). 

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

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