继续学习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).
感谢您的宝贵帮助。
答案 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
中的空列表元素数为K
,R
}是K + 1
。
这在逻辑上也是正确的。
empties([X|L] , K):-
empties(L,K).
这条规则说明
如果列表
[X|L]
中的空列表元素的数量,则列表X
{无论K
是什么!}中的空列表元素的数量为L
是K
。
这肯定是不逻辑正确,这就是您的查询empties([[],[2],[2],[]],0).
成功的原因。如果X = []
,此规则仍然成功。第三个子句与empties([], 0)
的第一个子句一起,将允许empties(L, 0)
形式的任何查询,其中L
是一个列表,以便成功。在这种情况下,您必须强制X
不为空,以使规则意味着:
如果
[X|L]
不为空,列表K
中的空列表元素数为X
,列表中的空列表元素数L
为K
。
因此,您的第三条规则必须确保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.