Prolog 列表练习

Prolog list exercise

这是我的练习:在 prolog 中定义一个谓词,应用于整数列表 L,结果给出 L 中偶数元素的后继列表。

我写的代码只有当一个元素是偶数时才有效,谁能帮我找出我错在哪里?

even(X):- 0 is mod(X,2).
odd(X):- 1 is mod(X,2).

list_even([],[]).    
list_even([T|C],K):- even(T), E is T+1, list_even(C,K1), append(K1,E,X), K is X.
list_even([T|C],K):- odd(T),list_even(C,K).

您的代码中的一些缺陷是:

  • append(K1, E, X):这个目标应该附加两个列表来生成第三个列表;但是,E 只是一个元素,而不是列表。所以你需要写append(K1, [E], X).
  • K is X:该目标对变量X表示的算术表达式进行求值,并将其值与变量K统一;但是,X 是一个列表,而不是算术表达式。所以你需要删除它。

所以正确的代码如下:

list_even([], []).
list_even([T|C], K):- even(T), E is T+1, list_even(C, K1), append(K1, [E], K).
list_even([T|C], K):- odd(T), list_even(C, K).

示例:

?- list_even([1, 20, 3, 40, 5, 7, 8], Successors).
Successors = [9, 41, 21] ;
false.

注意在得到的答案中,后继出现的顺序是相反的(输入列表中第一个偶数元素是20,但它的后继21是输出列表中的最后一个元素).

所以更好的代码如下:

even_number_successors([], []).
even_number_successors([X|Xs], Successors) :-
   (   X mod 2 =:= 0
   ->  Y is X + 1,
       Successors = [Y|Ys]
   ;   Successors = Ys ),
   even_number_successors(Xs, Ys).

示例:

?- even_number_successors([1, 20, 3, 40, 5, 7, 8], Successors).
Successors = [21, 41, 9].

根据你的问题陈述,

define a predicate in prolog which, applied to a list L of integers, gives as a result the list of the successors of the even elements present in L.

  • 从表面上看,你不需要odd/1:不是偶数就是奇数。

  • 为什么要用append/3?您只是 iterating/filtering 一个列表并正在构建一个新列表,对吗?相反,您可以通过使列表不完整并带有未绑定的尾部来按顺序构建列表。当我们向下递归时,我们构建列表的尾部,或者通过将它与一个新列表统一,或者在最后,将它与空列表统一,即原子 []).

我会这样做:

list_even( []     , []     ) .  % empty list? All done.
list_even( [X|Xs] , [Y|Ys] ) :- % non-empty?
  even(X),                      % - is X even? if so...
  !,                            % - eliminate the choice point
  Y is X+1,                     % - get the successor of X
  list_even(Xs,Ys)              % - recurse down
  .                             %
list_even( [_|Xs] ,    Ys  ) :- % Otherwise, the head of the list is odd: discard the head, and...
  list_even(Xs,Ys)              % - recurse down
  .                             % Easy!

even(X) :- 0 =:= X .