使用prolog确定List中是否有相同数量的a和b项

时间:2015-03-08 23:31:26

标签: prolog

问题陈述:在Prolog中定义一个关系equal_a_b(L),其中equal_a_b(L) true 如果L包含相等数量的 a 和< strong> b 条款。

我编写代码来计算术语和b术语的数量,并检查a == b。如果a === b为false,则程序应输出。但是,当我测试我的代码时,它会输出yes,我不知道为什么。

以下是代码:

equal_a_b(L):-
   eqab(L, A, B),
   eqabn(A, B).

eqab([], 0, 0).
eqab([a|L], X, Y):- eqab(L, Z, A), X is Z + 1, Y is A + 0.
eqab([b|L], X, Y):- eqab(L, Z, A), X is Z + 0, Y is A + 1.
eqab([C|L], X, Y):- eqab(L, Z, A), X is Z + 0, Y is A + 0. 

eqabn(A, B):- A==B.

以下是跟踪程序(equal_a_b([a])。它应该输出no:

| ?- trace, equal_a_b([a]).
The debugger will first creep -- showing everything (trace)
  1    1  Call: equal_a_b([a]) ? 
  2    2  Call: eqab([a],_85,_86) ? 
  3    3  Call: eqab([],_110,_111) ? 
  3    3  Exit: eqab([],0,0) ? 
  4    3  Call: _138 is 0+1 ? 
  4    3  Exit: 1 is 0+1 ? 
  5    3  Call: _166 is 0+0 ? 
  5    3  Exit: 0 is 0+0 ? 
  2    2  Exit: eqab([a],1,0) ? 
  6    2  Call: eqabn(1,0) ? 
  7    3  Call: 1==0 ? 
  7    3  Fail: 1==0 ? 
  6    2  Fail: eqabn(1,0) ? 
  2    2  Redo: eqab([a],1,0) ? n

(10 ms) yes

感谢任何帮助,谢谢。

2 个答案:

答案 0 :(得分:2)

equal_a_b(Xs) :-
   equals_a_b__n(Xs, 0).

equals_a_b__n([], 0).
equals_a_b__n([C|Cs], N0) :-
   char_n_(C, N0,N1),
   equals_a_b__n(Cs, N1).

char_n_(C, N, N) :-
   dif(C,a),
   dif(C,b).
char_n_(a, N0, N) :-
   N is N0 + 1.
char_n_(b, N0, N) :-
   N is N0 - 1.

这个解决方案是真正的关系,你甚至可以问

  

告诉我包含相同数量字符ab的所有列表。

| ?- length(Xs, N), equal_a_b(Xs).
   Xs = [], N = 0
;  Xs = [_A], N = 1,
   dif(_A,a), dif(_A,b)
;  Xs = [_A,_B], N = 2,
   dif(_A,a), dif(_A,b), dif(_B,a), dif(_B,b)
;  Xs = [a,b], N = 2
;  Xs = [b,a], N = 2
;  Xs = [_A,_B,_C], N = 3,
   dif(_A,a), dif(_A,b), dif(_B,a), dif(_B,b), dif(_C,a), dif(_C,b)
;  Xs = [_A,a,b], N = 3,
   dif(_A,a), dif(_A,b)
;  Xs = [_A,b,a], N = 3,
   dif(_A,a), dif(_A,b)
;  Xs = [a,_A,b], N = 3,
   dif(_A,a), dif(_A,b)
;  Xs = [a,b,_A], N = 3,
   dif(_A,a), dif(_A,b)
;  Xs = [b,_A,a], N = 3,
   dif(_A,a), dif(_A,b)
;  Xs = [b,a,_A], N = 3,
   dif(_A,a), dif(_A,b)
...

然后,它在当前的实现中也更有效。事实上,如果地面列表Xs的长度为 l ,则只需要与log l 成比例的空间,而您和@lurker&#39 ; s解决方案需要与 l 成比例的空间。

答案 1 :(得分:0)

潜伏者指出,当你看到'a'或'b'时,你的程序必须避免使用'catchall'规则。我能想到的更简单的补丁:用剪切提交选择。这是一个:

...
eqab([a|L], X, Y):- eqab(L, Z, A), !, X is Z + 1, Y is A + 0.
...

但如果您“反转”控制流程,则整体会更简单:倒数并检查,当列表变空时,如果计数匹配。