在Prolog列表中列出空列表

时间:2017-03-11 16:28:37

标签: list prolog

继续学习Prolog,

我使谓词empties(L,R)接受L中的组列表(即:[ [ 2 ] ,[ 1 ] ,[ ] ]),R表示组内空组的数量,因此对于此特定它应该去

empties([[2],[1],[]],1)
对于这个特殊情况,它给出了“是”,这似乎是有道理的。

如果我问:

empties([[],[2],[2],[]],X).

它会回答X = 2,这也是有道理的,但是当我用0替换X时,它也给出了一个肯定,我无法理解为什么。它似乎在问“至少是X”,而不是确切地说是出现次数。

这是代码:

isit([]).
empties([],0).
empties([X|L] , R):-
        isit(X),
        empties(L,K),
        R is K+1.

empties([X|L] , K):-
        empties(L,K).

感谢您的宝贵帮助。

3 个答案:

答案 0 :(得分:2)

您想要的是一组定义空列表元素数量的规则。理想情况下,这些应该(a)给你所有正确的答案,(b)不给你不正确的答案,(c)希望不给你答案重叠(多次提供相同的答案)。

您的empties/2谓词有三个子句,我们将对此进行检查。

empties([],0).

这个说

  

空列表没有空列表元素。

这在逻辑上是正确的。

empties([X|L] , R):-
    isit(X),
    empties(L,K),
    R is K+1.

这可以改写/简化:

empties([[]|L], R) :-
    empties(L, K),
    R is K + 1.

这就是说

  

如果列表[[] | L]中的空列表元素数为R,则L中的空列表元素数为KR }是K + 1

这在逻辑上也是正确的。

empties([X|L] , K):-
    empties(L,K).

这条规则说明

  

如果列表[X|L]中的空列表元素的数量,则列表X {无论K是什么!}中的空列表元素的数量为LK

这肯定是逻辑正确,这就是您的查询empties([[],[2],[2],[]],0).成功的原因。如果X = [],此规则仍然成功。第三个子句与empties([], 0)的第一个子句一起,将允许empties(L, 0)形式的任何查询,其中L是一个列表,以便成功。在这种情况下,您必须强制X不为空,以使规则意味着:

  

如果[X|L] 为空,列表K中的空列表元素数为X,列表中的空列表元素数LK

因此,您的第三条规则必须确保X不是空列表才能正确满足。这可以这样做:

empties([X|L] , K) :-
    X \= [],
    empties(L,K).

或者,你可以这样更优雅地做到这一点:

empties([[_|_]|L], K) :-
    empties(L, K).

[_|_]是一个或多个元素的匿名列表。

答案 1 :(得分:1)

您了解如何将列表分开:

[X|L]

您了解如何使用递归:

empties([X|L] , R):-
    ...
    empties(L,K),

您了解递归的基本情况:

empties([],0).

您了解如何使用Prolog进行算术运算:

R is K+1

您使用的是guards,无论您是否知道:

empties([],0)    % [] is the guard 

因此,您拥有解决此问题所需的基本机制,但将这些部分放在一起与Prolog合作可以解决您的问题。

解决方案

以下解决方案的关键是使用两个相互补充的保护语句,这意味着只能选择一个或另一个。将它们视为if语句,因为它们选择一个或另一个谓词。一旦你了解了Prolog在Prolog中的工作方式,在做Prolog时就不会将它们视为if语句,因为你会开始从程序上思考而不是逻辑上思考哪些不好;他们能够做得更多。

H == []
H \= []

它还通过谓词对计数变量R进行线程化。

empties([], R, R).

empties([H|T], R0, R) :-
    H == [],
    R1 is R0 + 1,
    empties(T, R1, R).

empties([H|T], R0, R) :-
    H \= [],
    empties(T, R0, R).

empties(L,R) :-
    empties(L,0,R).

输出

?- empties([],X).
X = 0.

?- empties([[]],X).
X = 1 ;
false.

?- empties([[],[a]],X).
X = 1 ;
false.

?- empties([[a],[]],X).
X = 1 ;
false.

?- empties([[],[]],X).
X = 2 ;
false.

?- empties([[a],[],[b]],X).
X = 1 ;
false.

?- empties([[],[a],[b]],X).
X = 1 ;
false.

?- empties([[a],[b],[]],X).
X = 1 ;
false.

?- empties([[],[],[]],X).
X = 3 ;
false.

答案 2 :(得分:1)

以下是使用findall/3谓词的另一种方法:

empties(L,N):-findall(X, (member(X,L),X = []) ,L1),length(L1,N).

上述解决方案的作用是找到所有X,它们是L的成员并且是空列表并将其添加到L1,然后返回L1的长度。

示例:

?- empties([[],[2],[2],[]],X).
X = 2.

?- empties([],X).
X = 0.

?- empties([[]],X).
X = 1.

?- empties([[],[_]],X).
X = 1.

?- empties([[],[2],[2],[]],2).
true.