简体   繁体   English

如何使TuProlog识别无效事实?

[英]How to make TuProlog recognize invalid facts?

I have following two Prolog files: 我有以下两个Prolog文件:

ontology.pl: Ontology.pl:

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

invalidFile.pl: 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 is invalid because it violates the rule specified in ontology.pl that all GuestPostId s must be unique. invalidFile.pl是无效的,因为它违反了中指定的规则ontology.pl所有GuestPostId s必须是唯一的。

When I load that data into my engine, I except it to throw some exception indicating that the data are invalid. 当我将数据加载到引擎中时,我会抛出异常,表明数据无效。 But it doesn't. 但事实并非如此。

What am I doing wrong? 我究竟做错了什么? How can I make sure that when I feed invalid data to TuProlog engine, I get notification of some sort (eg an exception or some flag) ? 如何在将无效数据提供给TuProlog引擎时确保得到某种通知(例如,异常或某些标志)?

Here's the relevant fragment of my code (you can find the entire code 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;
}

To set data integrity constraints on a Prolog table of facts, you need to approach this differently. 要在事实的Prolog表上设置数据完整性约束,您需要采用不同的方法。 I would suggest you first try to do it in pure Prolog, without the Java bits, just to get some understanding of what is going on. 我建议您首先尝试使用纯Java语言的Prolog进行操作,只是为了了解正在发生的事情。

If the database is static and does not change, it is easy: just load it, then run queries against it that do the data integrity checks. 如果数据库是静态的并且不会更改,则很容易:只需加载它,然后对它运行查询以进行数据完整性检查。 For example, you have a table site/1 with a single column, and you want to make sure that all values are strings: 例如,您有一个包含单个列的表site/1 ,并且您想确保所有值都是字符串:

There is no site(S) so that S is not a string 没有site(S)因此S不是字符串

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

If you want to wrap this into a predicate, you must name the predicate with a different name than your table! 如果要将其包装为谓词,则必须使用与表不同的名称来命名谓词!

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

Or, for the other one, a unique column (primary key): 或者,对于另一个,唯一列(主键):

There are no duplicates among the first arguments to guest_post_published/4 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

You probably need to wrap this up in a predicate of its own, too. 您可能也需要将其包装成自己的谓词。

If you want to check the validity of "alleged" facts before asserting them, you would want to read, rather than consult, the file and attempt to call each alleged fact to see if it succeeds. 如果要在断言“事实”的事实之前检查其有效性,则需要读取而不是查阅文件,并尝试调用每个所谓的事实以查看其是否成功。

As a very simple example, you can do the following: 作为一个非常简单的示例,您可以执行以下操作:

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

The call(TestFact) will succeed if the term read from invalidFile.pl succeeds given your existing facts and rules, otherwise it will fail. 给定您现有的事实和规则,如果从invalidFile.pl读取的术语成功,则call(TestFact)将成功,否则它将失败。 You can use this sequence and read all of the alleged facts and test them: 您可以使用此顺序并阅读所有所谓的事实并进行测试:

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).

In this case, validate_file will fail if any term in the file is false. 在这种情况下,如果文件中的任何术语为false, validate_file将失败。 As an exercise, you can make this smarter by tracking a "term count" or something like that in read_terms and write a predicate that checks a term and feeds back the term number if it fails so you can see which one(s) fail. 作为练习,您可以通过跟踪“ term count”或类似read_terms来使其变得更聪明,并编写一个谓词来检查一个术语,并在失败时反馈该术语号,以便您查看哪个或哪些失败。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM