简体   繁体   English

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

[英]Prolog - Add element to List in a recursive predicate

I need to build a Prolog predicate which returns in Books2009 a list of books that were published in the year of 2009, and in Books2014, the books published in 2014. 我需要建立一个Prolog谓词,它在Books2009中返回了2009年出版的书籍列表,以及2014年出版的Books2014书籍。

setbooks : will only be used to "create" the list of books that will be used in the predicate booksList_2009_2014. setbooks :仅用于“创建”将在谓词booksList_2009_2014中使用的书籍列表。
booksList_2009_2014(L, Books2009, Books2014) : this is the predicate we are trying to create and run ("L" is a list of books previously set in setbooks ). booksList_2009_2014(L,Books2009,Books2014) :这是我们试图创建和运行的谓词(“L”是以前在setbooks中设置的书籍列表)。

My code explanation : I tried to make the predicate insertAtEnd (which would be used later, inside booksList_2009_2014 ) that will insert an element in the end of a list. 我的代码解释 :我试图使谓词insertAtEnd (稍后将在booksList_2009_2014中使用 )将在列表的末尾插入一个元素。
Then I wrote the predicate booksList_2009_2014 for the simplest case (recieving an empty list of books), then for recieving a list of books with 1 element only, and then, a recursive case that would do the job for a list of books no matter how long it is. 然后我为最简单的情况编写了谓词booksList_2009_2014 (收到一个空的书籍清单),然后收到一个只有1个元素的书籍列表,然后是一个递归案例,无论如何都可以完成一系列书籍的工作很久了。

This is my code file: 这是我的代码文件:

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

Im not sure, but I think the code isnt correct somewhere in the recursive code: 我不确定,但我认为代码在递归代码中的某处是不正确的:

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

When I type setbooks(L),booksList_2009_2014(L,Books2009, Books2014) , the program is returning me just the last book of the list.. For example: 当我输入setbooks(L),booksList_2009_2014(L,Books2009,Books2014)时 ,程序只返回列表的最后一本书。例如:

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

Can someone help me? 有人能帮我吗? Pleeeasse??? Pleeeasse ???

The rule 规则

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

Keeps peeling off books one at a timeuntil you get to the rule when there is one item in the list 当列表中有一个项目时,只要你达到规则,就可以一次剥掉一本书

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

which of course unifies with the last book in the list, since it peels off the head continuously. 这当然与列表中的最后一本书结合在一起,因为它不断地消除了头部。 Then, since you haven't made a call using the head element in the first aforemention rule, it unifies Books2009 with the one call to insertAtEnd since the year is 2009. 然后,由于您没有使用第一个前述规则中的head元素进行呼叫,因此它将Books2009与insertAtEnd的一次调用统一起来,因为这一年是2009年。

You need to 你需要

  • Do something with the head element you peel off (Maybe make a different predicate that takes a single book) 使用你剥离的头部元素做一些事情 (也许制作一本不同的谓词,只需要一本书)
  • Possibly make an accumulator to pass around for your books 2009 and 2014 可能会使累加器传递给您的书籍2009年和2014年

So you are trying to select from an input list elements that satisfy one of two conditions and put them in one of two resulting lists: 因此,您尝试从满足两个条件之一的输入列表元素中进行选择,并将它们放在两个结果列表中的一个中:

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

Base case: your input list is empty; 基本情况:您的输入列表为空; so the results are empty, too. 所以结果也是空的。 Conditions can be ignored. 条件可以忽略。

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

The head of the list satisfies condition 1: 列表的头部满足条件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).

The head of the list satisfies condition 2: 列表的头部满足条件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).

The head does not satisfy either of the two conditions: 头部不满足以下两个条件中的任何一个:

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

For your case, you could write satisfies(X, Condition) for example as: 对于您的情况,您可以编写satisfies(X, Condition) ,例如:

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

So, you can then query: 那么,您可以查询:

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

Can you change this to work correctly for conditions that are not mutually exclusive? 你可以改变它,以便在不相互排斥的条件下正常工作吗? And what will happen if you skip the requirement in the last clause that neither condition is satisfied? 如果你跳过最后一句中既不满足条件的要求,会发生什么? How can you parametrize the way conditions are evaluated? 您如何参数化评估条件的方式? How can you parametrize the number of conditions and resulting lists? 如何参数化条件数和结果列表?

How to explain ? 如何解释 ? You are reversing the CONS operation WRT the control flow... and insertAtEnd anyway it's the wrong approach in Prolog, since it's a language with immutable (assign once) variables. 你正在逆转CONS操作WRT控制流...而insertAtEnd无论如何它都是Prolog中的错误方法,因为它是一个带有不可变 (赋值一次)变量的语言。

You could write 你可以写

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

but hardcoding data into logic it's the wrong approach in any language, and much more in Prolog. 但是将数据硬编码到逻辑中它是任何语言中的错误方法,而在Prolog中则更多。 No matter how your task is simple by now, a better approach would avoid binding vars to specific years'books. 无论你的任务如何简单,一个更好的方法将避免将vars绑定到特定的年份书。 Keeping it declarative: 保持声明:

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

and now 现在

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

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

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