【发布时间】:2013-12-18 20:48:09
【问题描述】:
我需要删除第一个列表中的所有偶数并将其余的保存到第二个列表中。 我的第一个非工作方法是:
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).
UPDATE2:迷失了逻辑:
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.
UPDATE3:遵循了建议,但仍然不起作用。
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).
UPDATE4:没有单例错误
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]).
UPDATE5: 让它工作了,但几乎不知道如何(一些魔法;)也许)。 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] 中删除了偶数元素.对吗?
【问题讨论】:
-
在您的第二个子句中,
H2和T2是单例的,这意味着您没有在规则中指出它们的来源。在第三个子句中,H1和H2都是单例的,所以在这种情况下你也没有完成规则中的逻辑。 -
在您的更新中,您的第二个子句
T(尾部)已经是一个列表。所以你不想要[T],而只想要T。在您的第三个子句中,H1和H2仍然是单例,现在T2也是。 -
在您的第二次更新中,您的第二个子句将允许
T包含偶数元素。换句话说,它表示如果E1是偶数,则删除偶数元素的列表[E1|T]是T。 换句话说,如果它是偶数,它会删除第一个元素,然后宣布胜利.除了将其包含在结果中之外,它并未指示如何处理T。我认为您的第三个子句看起来不错。 -
这就是 prolog 的工作原理。如果在提出解决方案时序言逻辑中有选择点,您按
;,它将寻求其他解决方案。当它找不到更多时,它会显示false或no(没有更多解决方案)。关于不知道您的程序如何工作,如果您按照我在回答中描述的方式考虑它应该是合乎逻辑的。例如,您的最后一个子句说,如果H是奇数,则删除偶数元素的[H|T1]是[H|T2],如果T2是从T1中删除偶数元素时得到的列表。这不合逻辑吗? :) -
在您对第 3 条的最后解释中,您是说,...两个列表的 IFF 头很奇怪... 但这并不完全正确。该子句对两个头都使用
H,因此头不仅奇数而且相同(它是相同的值),这很重要,因为我们希望第二个列表具有与第一个相同的值列表,而不是偶数。
标签: prolog