0

我是 Prolog 的新手,不是母语人士,所以如果你不理解我,我很抱歉。

我的问题是我怎样才能找到一个列表是否ab从一个列表中出现相同?

例如,[a,a,b,b]应该给我true,但如果其中一个出现的次数多于另一个,它应该给false。例如:[a,a,a,b,b]

任何人都可以帮助我吗?这是我到目前为止所拥有的,我知道这是错误的,但我正在尝试。

count(N,[],0).
count(N,[N|T],U) :-
   !,
   count(N,T,U1),
   U is U1+1.
count(N,[H|T],U) :-
   count(N,T,U).

occurrences([],[]).
occurrences([H|T],[[H,X]|Y]) :-
   count(H,[H|T],X),
   occurrences(T1,Y).
4

4 回答 4

2

这是带有if_/3=/3的更紧凑的occurrences/5 版本:

occurrences([],_A,_B,N,N).
occurrences([H|T],A,B,N0,M0) :-
   elem_x_count_(H,A,N1,N0),
   elem_x_count_(H,B,M1,M0),
   occurrences(T,A,B,N1,M1).

elem_x_count_(E,X,New,Old) :-
   if_(E=X, New is Old+1, New=Old).

在这个版本中,只有一个递归规则使用 elem_x_count_/4 来增加相应的计数器参数,如果列表的头部匹配A,则B分别或保持它们不变。调用谓词保持不变:

occurrences(List,A,B) :-
   dif(A,B),
   occurrences(List,A,B,0,0).

或者

occurrences(List) :-
   occurrences(List,a,b,0,0).

这样,如果所有三个参数都为基础,则谓词确定性地成功(由于没有选择点打开,因此无需按下;之后)。true这是旧版本的示例查询,出现次数/3:

?- occurrences([a,a,b,b],a,b).
true.

另一个区别是 diff/2 约束的数量较少。例如:

?- occurrences([a,a,b,b,c,c,d],X,Y).
X = a,
Y = b ;
X = a,
Y = c ;
X = b,
Y = a ;
X = c,
Y = a ;
X = b,
Y = c ;
X = c,
Y = b ;
dif(X, d),
dif(X, c),
dif(X, b),
dif(X, a),
dif(X, Y),
dif(Y, d),
dif(Y, c),
dif(Y, b),
dif(Y, a).

只有这个查询的最后一个解决方案与我以前的版本不同。它描述了相同的结果,但在另一个版本中出现两次的所有差异现在只出现一次。其他示例查询产生相同的答案。

于 2017-11-15T18:40:07.803 回答
1

如果第二个和第三个参数在作为第一个参数的列表中同样频繁地出现,您可以编写一个谓词occurrences/5 为真。第 4 和第 5 个参数是对应的计数器。那么谓词occurrences/1 是调用谓词:

occurrences(List) :-
   occurrences(List,a,b,0,0).

occurrences([],_A,_B,N,N).       
occurrences([A|Xs],A,B,N0,M) :-  
   N1 is N0+1,                   
   occurrences(Xs,A,B,N1,M).     
occurrences([B|Xs],A,B,N,M0) :-
   M1 is M0+1,
   occurrences(Xs,A,B,N,M1).
occurrences([X|Xs],A,B,N,M) :-
   dif(A,X),
   dif(B,X),
   occurrences(Xs,A,B,N,M).

您从 0 处的计数器开始,并取决于列表的头部等于AB相应的计数器增加,或者如果头部与两者不同,则不增加计数器。现在让我们看看您给定示例的结果:

?- occurrences([a,a,b,b]).
true ;
false.

?- occurrences([a,a,a,b,b]).
false.

但是,我认为让您指定两个元素的谓词occurrences/3 会更有用:

occurrences(List,A,B) :-
   dif(A,B),                     
   occurrences(List,A,B,0,0).    

然后您的示例查询将如下所示:

?- occurrences([a,a,b,b],a,b).
true ;
false.

?- occurrences([a,a,a,b,b],a,b).
false.

您还可以询问哪些元素同样经常出现:

?- occurrences([a,a,b,b,c,c,d],X,Y).
X = a,
Y = b ;
X = a,
Y = c ;
X = b,
Y = a ;
X = c,
Y = a ;
X = b,
Y = c ;
X = c,
Y = b ;
dif(X, d),
dif(X, c),
dif(X, c),
dif(X, b),
dif(X, b),
dif(X, a),
dif(X, a),
dif(X, Y),
dif(Y, d),
dif(Y, c),
dif(Y, c),
dif(Y, b),
dif(Y, b),
dif(Y, a),
dif(Y, a).

最后一个解决方案对应于两个根本没有出现在列表中的元素,因为它们都出现的频率相同,即 0 次。如果您想在另一个方向使用谓词,即询问哪些列表使得两个给定元素出现的频率相同,您必须在谓词时为限制列表长度的目标添加前缀打电话,例如:

?- length(L,_),occurrences(L,a,b).
L = [] ;
L = [_G150],
dif(_G150, b),
dif(_G150, a) ;
L = [a, b] ;
L = [b, a] ;
L = [_G116, _G119],
dif(_G116, b),
dif(_G116, a),
dif(_G119, b),
dif(_G119, a) ;
L = [a, b, _G162],
dif(_G162, b),
dif(_G162, a) ;
L = [a, _G159, b],
dif(_G159, b),
dif(_G159, a) ;
L = [b, a, _G162],
dif(_G162, b),
dif(_G162, a) ;
.
.
.
于 2017-11-14T23:13:35.950 回答
0

你只有一个列表,所以起初你的模式匹配会失败,顺便说一句,我会这样尝试,我不会添加任何解释,这样你就可以自己弄清楚它是如何工作的。

count(List):-
  count(List,0,0).

count([],L,L).


count([H|T],L,R):-
  (   
   H == 'a' ->
      NewL is L + 1,
      count(T,NewL,R)
    )
     ;
   (
     H == 'b' ->
       NewRight is R + 1,
       count(T,L,NewRight)
    ).
于 2017-11-14T23:10:24.150 回答
0

您可以在访问时从列表的尾部选择匹配元素(它必须存在),而不是计数。

递归基本情况将是您能想到的最简单的情况......并且select /3 是内置的,它将为您的问题提供一个非常紧凑的解决方案。

编辑

好吧,代码很简单...

occurrences([],[]).
occurrences([H|T],R) :- select(H,T,U), occurrences(U,R).

注意:成功时,R 将是空列表

于 2017-11-14T23:04:17.080 回答