我有两个Prolog文件:
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
必须是唯一的。
当我将数据加载到我的引擎中时,除了它之外,它会抛出一些异常,表明数据无效。但事实并非如此。
我做错了什么?如何确保在向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;
}
答案 0 :(得分:1)
要在Prolog事实表上设置数据完整性约束,您需要采用不同的方法。我建议你首先尝试在没有Java位的纯Prolog中进行,只是为了了解正在发生的事情。
如果数据库是静态的并且没有更改,则很容易:只需加载它,然后针对它执行数据完整性检查的查询。例如,您有一个包含单个列的表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 :(得分: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).
在这种情况下,如果文件中的任何字词为false,则validate_file
将失败。作为练习,您可以通过跟踪{term 1}中的“术语计数”或类似内容来使这更聪明,并编写一个检查术语的谓词,如果失败则反馈术语编号,这样您就可以看到哪一个( s)失败。