序言:遍历列表A的元素并与列表B的成员进行比较

时间:2019-04-16 03:02:12

标签: prolog

我正在尝试第一次编写Prolog逻辑,但是遇到了麻烦。我要编写一个逻辑,该逻辑接受两个列表并检查两者之间的相似元素。例如,考虑谓词similarity/2

?- similarity([2,4,5,6,8], [1,3,5,6,9]).
true.

?- similarity([1,2,3], [5,6,8]).
false.

第一个查询将返回true,因为这两个列表共有5和6。第二个返回false,因为该查询中的两个列表之间没有公共元素。

我不能使用内置的逻辑,例如成员,不相交,交集等。我正在考虑遍历提供的第一个列表,并检查它是否与第二个列表中的每个元素匹配。这是解决此问题的有效方法吗?我将不胜感激任何建议和帮助。非常感谢。

1 个答案:

答案 0 :(得分:1)

第一次编写Prolog确实令人生畏,因为它与您很可能会遇到的许多传统编程语言不同。但是,一旦您掌握了这种新型编程风格,这将是一次非常有益的体验!由于您提到您是第一次编写Prolog ,因此,我将提供一些有关编写Prolog的一般性提示和技巧,然后继续介绍您的问题,然后提供我认为的建议。解决方案。


递归思考

您可以认为编写的每个Prolog程序本质上都是递归的。即,您可以为其提供一系列“基本情况”,其格式如下: 我认为human(John).wildling(Ygritte)应该始终是您编写的第一个规则。尝试将问题分解为最简单的情况,然后从那里开始工作。

另一方面,您也可以为其提供更复杂的规则,它们看起来像这样:contains(X, [H|T]):- contains(X, T)关键一点是,编写这样的规则与在Python中编写递归函数非常等效。在查看值是否包含在列表中时,此规则的工作量很大,但是如果没有“基本情况”,它就不完整。一个完整的包含规则实际上是将两个规则合在一起:
contains(X, [X|_]).
contains(X, [H|T]):-contains(X, T).

这样做的主要好处是尝试确定问题的简单案例,这些案例可以像递归函数中的基本案例一样工作,然后尝试确定您要如何“递归”并实际解决手头的问题。


模式匹配

Prolog的一大优点是它具有适当的模式匹配系统。只要有可能,您都应该100%利用此优势,这对尝试对列表进行操作特别有用。例如:
head(X, [X|T]).
如此调用时将计算为true:head(1, [1, 2, 3]),因为规则中固有的是X的匹配。列表的第一个元素上的这种模式匹配非常重要,这实际上是完成任何工作的关键方式在Prolog列表中。根据我的经验,列表开头的模式匹配通常是我之前提到的“基本情况”之一。


了解程序的流程

Prolog工作方式的另一个关键组成部分是采用“自上而下”的方式读取代码。我的意思是,每次调用规则时(格式king(James).除外),Prolog从第1行开始,一直持续到达到真实的规则或文件末尾为止。因此,规则的排序非常重要。我假设您知道可以通过逗号将规则组合在一起以指示逻辑与,但是更微妙的是,如果您将一个规则放在另一个之上,则它可以充当逻辑或,仅因为它将在另一个规则之前进行评估,并可能导致程序递归。


具体示例

现在,我已经摆脱了所有一般性建议,实际上我将参考给定的问题。首先,我要写“基本情况”。如果为您提供了两个第一个元素相同的列表,将会怎样?
如果每个列表中的第一个元素都不相同,则它们必须不同。因此,您必须浏览第二个列表以查看此元素是否包含在列表其余部分中的任何位置。这会产生什么样的规则?
或者可能是第一个列表的第一个元素根本不包含在第二个列表中,在这种情况下,您必须在第一个列表中前进一次,然后从第二个列表重新开始。 会产生什么样的规则?
最后,我想说您的方法是正确的方法,下面我提供了自己的解决方案:

  

similarity([H|_], [H|_]).
 similarity(H1|T1], [_|T2]):- similarity([H1|T1], T2).
 similarity([_|T1], [H2|T2]):- similarity(T1, [H2|T2]).

希望所有这些以某种方式有所帮助!