我需要从第一个列表中删除所有的偶数并将剩余部分保存到第二个列表中。 我的第一种不起作用的尝试是:
remove_even([],[]).
remove_even([H1|T1],[H2|T2]):-
H1 mod 2 =:= 0,
remove_even(T1,_).
remove_even([H1|T1],[H2|T2]):-
remove_even(T1,T2).
以下是在SWI-Prolog 7.1.37中运行的示例查询:
?- remove_even([1,2,3,4],NewList).
NewList = [_G252, _G255|_G256]. % BAD! expected: NewList = [1,3]
我的代码出了什么问题?
更新:下一次尝试,它没有起作用,因为remove_even
一旦检查到它是有效的偶数,就会返回false并转到另一个规则,在那里递归发生...
remove_even([],[]).
remove_even([El|T],[T]):- El mod 2 =:= 0.
remove_even([H1|T1],[H2|T2]):-
remove_even(T1,T1).
更新2: 在逻辑上迷失了:
remove_even([],[]).
remove_even([El|T],T):-El mod 2 =:= 0. % removing the head if head is even
remove_even([H|T1], [H|T2]) :- % case where head is odd
H mod 2 =\= 0, % rules that ensure head is odd
remove_even(T1, T1).
% just copying T1 from source list to destination,
% will look up T1 values in next recursive iteration when it becomes a H.
更新3:按照建议进行了操作,但仍然无法正常工作。
remove_even([],[]).
remove_even([El|T], NewT) :- El mod 2 =:= 0, remove_even(T, NewT).
remove_even([H|T1], [H|T2]) :- H mod 2 =\= 0, remove_even(T1, T1).
更新4:无单例错误
remove_even([],[]).
remove_even([El|T], NewT) :- El mod 2 =:= 0, remove_even(T, NewT).
remove_even([El|T1], NewT) :- El mod 2 =\= 0, remove_even(T1,[NewT|T1]).
更新5: 已经使其正常工作,但几乎不知道如何做到这一点(可能是一些魔法;))。gtrace
很好,但有一个Prolog可以绘制某种决策树或易于理解的图形表示它的步骤会更有用。
remove_even([],[]).
remove_even([El|T], NewT) :- El mod 2 =:= 0, remove_even(T, NewT).
remove_even([H|T1], [H|T2]) :- H mod 2 =\= 0, remove_even(T1, T2).
如何在考虑递归调用的情况下解释逻辑上的最后一个子句? 我的尝试:
[H|T2]
是从 [H|T1]
中删除偶数元素后得到的列表当且仅当两个列表的头部都是奇数,并且目标列表的尾部 T2
是一个 T1
的尾部,其中所有偶数元素已被删除。正确吗?
H2
和T2
是单例,这意味着你没有在规则中指明它们来自哪里。在第三个从句中,H1
和H2
都是单例,因此在这种情况下你也没有完成规则中的逻辑。 - lurkerT
(一个尾部)已经是一个列表。所以你不需要[T]
而只需要T
。在你的第三个子句中,H1
和H2
仍然是单例,现在T2
也是。 - lurkerT
具有偶数元素。换句话说,它表示*如果E1
是偶数,则从列表[E1|T]
中删除偶数元素后得到的结果是T
*。换句话说,如果第一个元素是偶数,则删除它并宣布胜利。除了将其包含在结果中之外,它不指示如何处理T
。我认为你的第三个条款看起来很好。 - lurkerH
是奇数,并且T2
是从T1
中删除偶数元素时得到的列表,则去除偶数元素后的偶数元素已被删除,即[H|T1]
与[H|T2]
相同。这难道不是合乎逻辑的吗? :) - lurkerH
表示头部,因此这些头部不仅是奇数,而且是相同的(它们具有相同的值),这很重要,因为我们希望第二个列表与第一个列表具有相同的值,只是没有偶数值。 - lurker