在Prolog中比较KB中事实的元素/参数?

时间:2015-01-07 13:41:46

标签: prolog logic

这是正在使用的知识库。

localLib('AHorowitz', 'Stolen Gods', 2011, 'Scorpia Rising', 448, 4).
localLib('AHorowitz', 'Night Visitors', 2000, 'Stormbreaker', 240, 2).
localLib('AHorowitz', 'Matador', 2003, 'Eagle Strike', 340, 6).
localLib('AJohnston', 'Night Visitors', 2000, 'Stormbreaker', 240, 2).
localLib('AJohnston'’, 'Matador', 2003, 'Eagle Strike', 340, 6).
localLib('RMuchamore', 'Basic Training', 2007, 'The Recruit', 342, 3).
localLib('MHaddon', '11.', 2004, 'The Curious Incident Of The Dog In The Night Time', 226, 5).

KB的关键如下:

localLib(w, e, y, t, n, c) where
w = writer’s name
e = excerpt in text
y = year of text
t = title of text
n = no. of pages in excerpt 
c = no. of acknowledgements

我必须写一条规则来查找给定作者发布的单个最长摘录的页数是多少?

虽然我理解这个问题以及最终输出应该是什么样子,但我很难将其翻译成Prolog语言。 我在下面写的代码是规则的开始,因为我被困住了:

longestexcerpt(W, E, N):- localLib(W,E,_,_,N,_), sort(N,X). 

有效地我理解我们必须让Prolog检查每个页面中没有相互之间的页面,因此它就像一个排序算法,但是到目前为止我们在讲座中学到的排序功能只涉及列表中的排序数。如何让Prolog检查同一作者的每个摘录长度,比如'AHorowitz',然后让它显示最高的一个,在这种情况下n = 448(因为被盗的神是所有Horowitz文本中最长的页数)。

帮助和指导如何处理这些问题非常有用!

2 个答案:

答案 0 :(得分:2)

另一个解决方案也没问题,但您也可以这样做:

% The longest excerpt for an author
longest_excerpt(W, E, N) :-
    localLib(W, E, _, _, N, _),
    \+ (localLib(W, _, _, _, N1, _),
        N < N1).

其内容如下:&#34;有一个作者W,摘录E长度为N,并且没有来自同一作者的摘录长度&#34;

\+这是否定:将其视为,#34;当目标失败时成功。&#34;在这里,目标是结合。

从顶层:

?- longest_excerpt(W, E, N).
W = 'AHorowitz',
E = 'Stolen Gods',
N = 448 ;
W = 'AJohnston',
E = 'Matador',
N = 340 ;
W = 'RMuchamore',
E = 'Basic Training',
N = 342 ;
W = 'MHaddon',
E = '11.',
N = 226.

当然,使用setof/3并没有错。

至于来自@lurker的解决方案,它似乎更好,即使少了一点&#34;声明&#34;。我会把它写成:

longest_excerpt_1(W, E, N) :-
    setof(N0-E0, Y^T^C^localLib(W, E0, _, _, N0, _), R),
    last(N-E, R).

答案 1 :(得分:1)

正如您可能已经发现的那样,这里有一个谓词,对于作者,摘录和页数的任何关联都是如此:

longestexcerpt(W, E, N) :- localLib(W,E,_,_,N,_).

如果您想收集给定作者的列表中的所有解决方案,您可以这样做:

writer_excerpts(Writer, ExcerptList) :-
    setof( E-N, Y^T^C^localLib(Writer, E, Y, T, N, C), ExcerptList ).

存在量词,Y^T^C^表示我们不希望在结果中使用这些值。好的,那很棒。现在我们有ExcerptList的完整摘录列表(Writer),setof/3将按照自然顺序排列每个元素E-N&#34 ; (将按术语E进行整理)。也就是说,ExcerptList将是一个看起来像'Stolen Gods'-448等的元素列表。示例输出如下所示:

| ?- writer_excerpts('AHorowitz', E).

E = ['Matador'-340,'Night Visitors'-240,'Stolen Gods'-448]

yes

由于您需要最大数量的页面,因此您真的希望通过减少页数来排序。因此,您可以将N-E作为列表元素进行交换,通过增加页数来提供顺序,然后反转列表:

writer_excerpts(Writer, ExcerptList) :-
    setof( N-E, Y^T^C^localLib(Writer, E, Y, T, N, C), EList),
    reverse(EList, ExcerptList).

这会产生:

| ?- writer_excerpts('AHorowitz', E).

E = [448-'Stolen Gods',340-'Matador',240-'Night Visitors']

yes

最后,您只需要选择此谓词结果的第一个元素:

writers_most_excerpt_pages(Writer, Excerpt, Pages) :-
    setof( N-E, Y^T^C^localLib(Writer, E, Y, T, N, C), EList),
    reverse(EList, [Pages-Excerpt|_]).

在这里,我们将排序列表与[Pages-Excerpt|_]内联统一,因为我们只关心第一个元素的Pages-Excerpt信息。我们不关心列表的尾部(其余部分),所以我们只使用_