【问题标题】:determining if there are equal number of a and b terms in a List using prolog使用序言确定列表中是否有相同数量的 a 和 b 项
【发布时间】:2015-03-08 23:31:26
【问题描述】:

问题说明:在 Prolog 中定义一个关系,equal_a_b(L),如果 L 包含相等数量的 a 和 b 条款。

我编写了代码来计算 a 项和 b 项的数量,并检查 a==b。如果 a===b 为假,那么程序应该输出 no。但是,当我测试我的代码时,它输出是,我不知道为什么。

代码如下:

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

感谢您的帮助。

【问题讨论】:

  • [a] 将匹配 [C|L] 以及 [a|L]。您需要确保在最后一个子句中使用 C \= aC \= b。否则,它将导致 eqab([a], 0, 0) 为真。
  • 为简洁起见,您可以使用eqab([a|L], X, A) :- eqab(L, Z, A), X is Z + 1. 而不是eqab([a|L], X, Y):- eqab(L, Z, A), X is Z + 1, Y is A + 0.。同样适用于您的 eqab([b|L],...) 子句。

标签: prolog


【解决方案1】:
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)
...

然后,它在当前实现中也更有效。实际上,对于长度为 l 的地面列表 Xs,它只需要与 log l 成比例的空间,而您和 @lurker 的解决方案需要空间这与 l 成正比。

【讨论】:

    【解决方案2】:

    正如 lurker 所说,当你的程序“看到”“a”或“b”时,它必须避免“catchall”规则。我能想到的更简单的补丁:通过削减提交选择。这是一个:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-21
      • 1970-01-01
      • 2017-02-19
      • 1970-01-01
      • 2013-07-02
      • 1970-01-01
      相关资源
      最近更新 更多