如何使用Prolog删除列表中的偶数 [英] How to remove even numbers in List using Prolog

查看:62
本文介绍了如何使用Prolog删除列表中的偶数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要删除第一个列表中的所有偶数并将其余的保存到第二个列表中.我的第一个非工作方法是:

I need to remove all even numbers in first list and save the rest to second list. My first non-working approach was:

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 运行:

Sample query, run with SWI-Prolog 7.1.37:

?- remove_even([1,2,3,4],NewList).
NewList = [_G252, _G255|_G256].     % BAD! expected: NewList = [1,3]

我的代码有什么问题?

UPDATE:下一次尝试,它不起作用,因为 remove_even 曾经检查过它是否有效偶数,然后返回 false 并转到另一个发生递归的规则..

UPDATE: next try, it is not working because remove_even once checked if it's valid even, then returned false and went to another rule, where recursion took place...

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:遵循了建议,但仍然无效.

UPDATE3: followed recommendations but it still doesn't work.

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 绘制某种决策树或一些易于理解的步骤图形表示会很有用.

UPDATE5: got it working, but have almost no idea how (some magic ;) maybe ) . gtrace is good but would be useful to have Prolog to draw some kind of decision tree or some easily understandable graphical representation of it's steps.

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] IFF 两个列表的头是奇数和删除偶数元素的列表目标列表的尾部 T2 是一个尾部 T1 删除了所有偶数元素.正确吗?

How to interpret logically last clause taking into account recursion calls? My try: [H|T2] is a list with even elements removed from [H|T1] IFF Heads of both Lists is odd AND Tail T2 of destination list is a Tail T1 with all even elements removed. Correct?

推荐答案

您有单例变量警告这一事实表明存在问题.您的子句标题暗示您关心特定变量,但子句逻辑不会实例化它或以其他方式使用它.

The fact that you have singleton variable warnings is a clue that something isn't right. Your clause header implies you care about a particular variable, but the clause logic doesn't instantiate it or otherwise use it.

分析您提供的规则(条款)

Analyzing the rules (clauses) you provided

remove_even([],[]).

良好的规则.删除偶数的空列表是空列表.

remove_even([H1|T1],[H2|T2]):- 
    H1 mod 2 =:= 0,
    remove_even(T1,_).

这条规则说,[H2|T2] 是列表 [H1|T1] 如果 H1 删除偶数是偶数,如果我从 T1 中删除偶数并丢弃它们.这听起来不对.它也没有说明您将如何获得 H2.注意:如果逻辑没有规定,您可能不希望将此子句中的结果列表拆分为头和尾.

This rule says, [H2|T2] is the list [H1|T1] with even numbers removed if H1 is even, and if I remove the evens from T1 and discard them. That doesn't sound right. It also doesn't say how you are to obtain H2. Note: you may not want to split the result list in this clause into head and tail if the logic doesn't dictate.

remove_even([H1|T1],[H2|T2]):-
    remove_even(T1,T2).

此规则表示 [H2|T2][H1|T1] 如果 T2[H1|T1] 则删除偶数code>T1 去掉偶数.这听起来部分正确,但规则并未指明如何处理 H1H2.

This rule says that [H2|T2] is [H1|T1] with even numbers removed if T2 is T1 with the even numbers removed. That sounds partially correct, but the rule doesn't indicate how to handle H1 and H2.

UPDATE:在你的更新中,新的第二个子句:

UPDATE: in your update, the new second clause:

remove_even([El|T],[T]):- El mod 2 =:= 0.

这就更近了.一个问题是T 已经是一个列表,所以你不需要[T] 而只是T.然后变成:

This is closer. One problem is that T is already a list, so you don't want [T] but just T. Then it becomes:

remove_even([E1|T], T) :- E1 mod 2 =:= 0.

其中说:删除偶数元素的列表 [E1|T] 是列表 T 如果 E1 是偶数.这是一个正确的陈述,但不是完整的逻辑.它没有对T做任何规定.如果列表 T 有偶数元素怎么办?有关此特定条款的更正版本,请参阅 @Sergey 的回答.

Which says: The list [E1|T] with even elements removed is the list T if E1 is even. This is a correct statement but isn't complete logic. It doesn't make any stipulation about T. What if the list T has even elements? See @Sergey's answer for a corrected version of this specific clause.

您更新后的第三个条款有一些新问题:

Your updated third clause has some new issues:

remove_even([H1|T1],[H2|T2]):-
    remove_even(T1,T1).

有三个单例变量.规则说,[H1|T1] 删除偶数元素会产生 [H2|T2] 如果 T1 本身带有偶数元素移除(即,T1 没有偶数元素).这听起来根本不合逻辑.所以你需要重新考虑这个规则.我假设您打算在头为奇数的情况下(因为第 2 条涉及偶数头).在这种情况下,您只是将头部复制到结果列表中.您的子句标题应如下所示:

There are three singleton variables. The rule says, [H1|T1] with even elements removed yields [H2|T2] if T1 is itself with even elements removed (i.e., T1 has no even elements). That doesn't sound logical at all. So you need to rethink that rule. I assume you are intending the case where the head is odd (since clause 2 deals with an even head). In that case, you are just copying the head over to the result list. Your clause heading should then look like:

remove_even([H|T1], [H|T2]) :-   % case where head is odd
     % put rules here that ensure head is odd, and define how T1 and T2 are related

所以你最终会有 3 个子句:(1) 从空列表中删除偶数元素,(2) 从头部为偶数的列表中删除偶数元素,以及 (3) 从头部为偶数的列表中删除偶数元素很奇怪.这一切听起来很完整.遵循逻辑即可.

So you would ultimately have 3 clauses: (1) removing the even elements from an empty list, (2) removing even elements from a list whose head is even, and (3) removing the even elements from a list whose head is odd. That all sounds complete. Just follow the logic.

UPDATE4 响应:

新的第 3 条通过引入一些问题消除了单例:

The new 3rd clause eliminates a singleton by introducing some issues:

remove_even([El|T1], NewT):-         
    El mod 2 =\= 0,                     
    remove_even(T1, [NewT|T1]). 

通读:[E1|T1] 删除偶数元素是 NewT 如果 E1 是奇数并且 [NewT|T1] 是一个从 T1 中删除偶数元素的列表.这里的一个大问题是您使用 NewT(一个列表)作为另一个列表 [NewT|T1] 的头部,所以它现在是一个列表列表,它将不匹配任何东西.请参阅上文第 3 条的先前提示.此外,规则中不再有一部分说E1NewT 的一部分.如果 E1 是奇数,则当删除偶数元素时,它应该是另一个列表的一部分.

Reading through: [E1|T1] with even elements removed is NewT if E1 is odd and [NewT|T1] is a list with even elements removed from T1. A BIG problem here is that you are using NewT (a list) as the head of another list [NewT|T1], so it's now a list of lists, which will not match anything. See the prior hint for clause 3 above. In addition, there's no longer a part of the rule that says E1 is part of NewT. If E1 is odd, it should be part of the the other list when even elements are removed.

UPDATE5 响应(为什么现在有效?):

所以最终的工作版本是这样的:

So the final working version looks like this:

remove_even([],[]).

和以前一样:如果删除空列表的偶数元素,则会得到一个空列表.

As before: if you remove the even elements of an empty list, you get an empty list.

remove_even([El|T], NewT):- 
    El mod 2 =:= 0,
    remove_even(T, NewT).

NewT 是列表 [E1|T] 如果 E1 是偶数且 NewT 删除偶数元素是 T(原始列表的尾列表"),其中从 T 中删除了偶数元素.换句话说,我们删除了 E1(一个偶数元素,第一个列表的头部 - 我们不再需要它,因为它是偶数)并留下 T,我们想要处理"并找到类似于 T 的列表的其余部分,但删除了偶数元素.

NewT is the list [E1|T] with even elements removed if E1 is even and NewT is T (the "tail list" of the original list) with the even elements removed from T. In other words, we dropped E1 (an even element, head of the first list - we don't want it any more since it's even) and are left with T, the rest of the list which we want to "process" and find the list that's like T but with the even elements removed.

remove_even([H|T1], [H|T2]):-         
    H mod 2 =\= 0,                     
    remove_even(T1, T2).

我们之前已经介绍过这个,但为了完整起见:[H|T1] 删除偶数元素是 [H|T2] 如果 H 不是偶数,T1 删除了偶数元素后是 T2.你对这个子句的描述是,[H|T2] 是一个从 [H|T1] 中删除偶数元素的列表,两个列表的 IFF 头都是奇数,目标列表的尾 T2 是一个尾 T1,删除了所有偶数元素. 这不太准确.你是说,......两个列表的 IFF 头是奇数......",而在子句中,我们说头是 相同 和奇数(它是相同的数字),而不是只是两个都很奇怪.

We've covered this one before, but for completeness: [H|T1] with even elements removed is [H|T2] if H is not even and T1 with its even elements removed is T2. Your description of this clause reads, [H|T2] is a list with even elements removed from [H|T1] IFF Heads of both Lists is odd AND Tail T2 of destination list is a Tail T1 with all even elements removed. This isn't quite accurate. You're saying, "...IFF heads of both lists is odd...", whereas in the clause, we are saying the heads are identical and odd (it's the same number), not just both odd.

正如我之前在回答中进一步描述的那样,涵盖了所有情况.如果你从逻辑上考虑它,它是有道理的.:)

All of the cases are covered as I described further before in my answer. If you think about it logically, it makes sense. :)

这篇关于如何使用Prolog删除列表中的偶数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆