Prolog - 在递归谓词中向List添加元素

时间:2014-09-11 00:03:37

标签: list recursion prolog

我需要构建一个Prolog谓词,在Books2009中返回2009年出版的书籍列表,以及2014年出版的Books2014书籍。

setbooks :只会用于"创建"将在谓词booksList_2009_2014中使用的书籍列表 booksList_2009_2014(L,Books2009,Books2014):这是我们尝试创建和运行的谓词(" L"是以前在 setbooks中设置的书籍列表)。

我的代码说明:我尝试将谓词 insertAtEnd (稍后将在 booksList_2009_2014 中使用)插入元素在列表的末尾。
然后我为最简单的情况写了谓词 booksList_2009_2014 (收到一个空的书籍清单),然后收到一个只有1个元素的书籍列表,然后是一个递归的案例,可以完成这个工作。一本书清单无论多长时间。

这是我的代码文件:

setbooks([book('Name 5', 'Publisher ABC', date(12, 2014)), book('Name 4', 'Publisher ABC', date(05, 2009)), book('Name 3', 'Publisher ABC', date(02, 2009)), book('Name 6', 'Publisher ABC', date(03, 2013)), book('Name 2', 'Publisher ABC', date(12, 2014)), book('Name 1', 'Publisher ABC', date(06, 2009))]).

insertAtEnd(X,[ ],[X]).
insertAtEnd(X,[H|T],[H|Z]) :- insertAtEnd(X,T,Z).

booksList_2009_2014([],_,_).

booksList_2009_2014([book(Name,Publisher,date(M1,Y1))],Books2009, Books2014):-
    Y1=2014 -> insertAtEnd(book(Name,Publisher,date(M1,Y1)),_,Books2014);
    Y1=2009 -> insertAtEnd(book(Name,Publisher,date(M1,Y1)),_,Books2009).

booksList_2009_2014([H|T],Books2009, Books2014):-
    booksList_2009_2014(T,Books2009, Books2014).  

我不确定,但我认为代码在递归代码的某处不正确:

booksList_2009_2014([H|T],Books2009, Books2014):-
        booksList_2009_2014(T,Books2009, Books2014).  

当我输入 setbooks(L),booksList_2009_2014(L,Books2009,Books2014)时,程序只返回列表的最后一本书。例如:

Books2009 = [book('Name 1', 'Publisher ABC', date(06, 2009))] 

有人能帮助我吗? Pleeeasse ???

3 个答案:

答案 0 :(得分:1)

规则

booksList_2009_2014([H|T],Books2009, Books2014):-
booksList_2009_2014(T,Books2009, Books2014).  

当列表中有一个项目时,只要你达到规则,就可以一次剥掉一本书

booksList_2009_2014([book(Name,Publisher,date(M1,Y1))],Books2009, Books2014):-
    Y1=2014 -> insertAtEnd(book(Name,Publisher,date(M1,Y1)),_,Books2014);
    Y1=2009 -> insertAtEnd(book(Name,Publisher,date(M1,Y1)),_,Books2009).

当然,它与列表中的最后一个书籍相结合,因为它不断地消除了头部。然后,由于您还没有使用第一个上述规则中的head元素进行调用,因此它将自2009年以来一直使用一个调用insertAtEnd来统一Books2009。

你需要

  • 使用您剥离的头部元素某些(也许制作一本不同的谓词,只需一本书)
  • 可能会为2009年和2014年的图书传递累加器

答案 1 :(得分:1)

因此,您尝试从满足两个条件之一的输入列表元素中进行选择,并将它们放入两个结果列表中的一个:

% list_c1_c2_r1_r2(List, Condition1, Condition2, Result1, Result2)

基本情况:您的输入列表为空;所以结果也是空的。条件可以忽略。

list_c1_c2_r1_r2([], _, _, [], []).

列表的头部满足条件1:

list_c1_c2_r1_r2([X|Xs], C1, C2, [X|Ys], Zs) :-
    satisfies(X, C1),
    list_c1_c2_r1_r2(Xs, C1, C2, Ys, Zs).

列表的头部满足条件2:

list_c1_c2_r1_r2([X|Xs], C1, C2, Ys, [X|Zs]) :-
    satisfies(X, C2),
    list_c1_c2_r1_r2(Xs, C1, C2, Ys, Zs).

头部不满足以下两个条件之一:

list_c1_c2_r1_r2([X|Xs], C1, C2, Ys, Zs) :-
    \+ satisfies(X, C1),
    \+ satisfies(X, C2),
    list_c1_c2_r1_r2(Xs, C1, C2, Ys, Zs).

对于您的情况,您可以编写satisfies(X, Condition),例如:

satisfies(book(_, _, date(_, Year)), Year).

那么,您可以查询:

?- books(Books), list_c1_c2_r1_r2(Books, 2009, 2014, Book2009, Books2014).
Books = [book('Name 5', 'Publisher ABC', date(12, 2014)),
         book('Name 4', 'Publisher ABC', date(5, 2009)),
         book('Name 3', 'Publisher ABC', date(2, 2009)),
         book('Name 6', 'Publisher ABC', date(3, 2013)),
         book('Name 2', 'Publisher ABC', date(12, 2014)),
         book('Name 1', 'Publisher ABC', date(6, 2009))],
Book2009  = [book('Name 4', 'Publisher ABC', date(5, 2009)),
             book('Name 3', 'Publisher ABC', date(2, 2009)),
             book('Name 1', 'Publisher ABC', date(6, 2009))],
Books2014 = [book('Name 5', 'Publisher ABC', date(12, 2014)),
             book('Name 2', 'Publisher ABC', date(12, 2014))] .

您是否可以更改此设置以便在不相互排斥的条件下正常工作?如果你跳过最后一句中既不满足条件的要求,会发生什么?您如何参数化评估条件的方式?如何参数化条件数和结果列表?

答案 2 :(得分:1)

如何解释? 你正在逆转CONS操作WRT控制流程...... 和insertAtEnd无论如何它在Prolog中是错误的方法,因为它是一种语言 使用不可变(分配一次)变量。

你可以写

booksList_2009_2014([], [], []).
booksList_2009_2014([Book|Books], L2009, L2014) :-
  booksList_2009_2014(Books, L2009_t, L2014_t), % note: construct the tail(s) first
  Book = book(_,_,date(_,Year)),
  (  Year == 2009
  -> L2009 = [Book|L2009_t], L2014 = L2014_t
  ;  Year == 2014
  -> L2009 = L2009_t, L2014 = [Book|L2014_t]
  ;  % did you forgot year 2013 ?
     L2009 = L2009_t, L2014 = L2014_t
  ).

但是将数据硬编码到逻辑中它是任何语言中的错误的方法,而在Prolog中则更多。无论你的任务如何变得简单,一个更好的方法是避免将变量绑定到特定年份的书籍。保持声明:

books_of_year(AllBooks, Year, Result) :-
  Book = book(_,_,date(_,Year)),
  findall(Book, member(Book, AllBooks), Result).

现在

?- setbooks(L), books_of_year(L,2009,Books2009), books_of_year(L,2014,Books2014).
% L = ... not interesting
Books2009 = [book('Name 4', 'Publisher ABC', date(5, 2009)), book('Name 3', 'Publisher ABC', date(2, 2009)), book('Name 1', 'Publisher ABC', date(6, 2009))],
Books2014 = [book('Name 5', 'Publisher ABC', date(12, 2014)), book('Name 2', 'Publisher ABC', date(12, 2014))].