【问题标题】:Better pure version of same_length/2更好的纯版本 same_length/2
【发布时间】:2022-10-15 14:22:42
【问题描述】:

鉴于same_length/2 的频繁纯定义为

same_length([],[]).
same_length([_|As], [_|Bs]) :-
   same_length(As, Bs).

?- same_length(L, [_|L]).
   loops.

对于这种情况,是否有一个不循环的纯定义?类似于append/3 的纯(但效率较低)版本,称为append2u/3

我知道如何使用var/1 等手动捕获此类情况,但理想情况下,需要一个与原始定义一样纯的版本。或者至少它应该很简单。

我尝试的是上面的定义。

承诺:将赏金

一项澄清似乎是有序的:

请注意,某些查询本质上不得终止。考虑到:

?- same_length(Ls, Ks).
   Ls = [], Ks = []
;  Ls = [_A], Ks = [_B]
;  Ls = [_A,_B], Ks = [_C,_D]
;  Ls = [_A,_B,_C], Ks = [_D,_E,_F]
;  Ls = [_A,_B,_C,_D], Ks = [_E,_F,_G,_H]
;  ... .

没有其他方法可以使用句法答案替换语言枚举所有解决方案。

但是对于给定的查询,仍然可能会终止一个实现。

【问题讨论】:

  • 添加same_length(L, L) :- \+ length(L, _), !, false. 的第一个子句似乎可以解决问题,但它并不纯粹。
  • ...如果发生检查被禁用。
  • 甚至没有,请参阅#26 所有系统要么循环,要么产生资源错误,要么产生类型错误。

标签: prolog logical-purity


【解决方案1】:

使用'$skip_max_list'/4 的解决方案:

% Clause for `?- L = [a|L], same_length(L, _)`.
same_length(As, Bs) :-
    (Cs = As ; Cs = Bs),
    '$skip_max_list'(_, _, Cs, Cs0),
    subsumes_term([_|_], Cs0), !,
    false.
% Clause for `?- same_length(L, [_|L])`.
same_length(As, Bs) :-
    As == Bs,
    '$skip_max_list'(S, _, As, As0),
    '$skip_max_list'(T, _, Bs, Bs0),
    As0 == Bs0,
    S == T, !,
    false.
same_length(As, Bs) :-
    same_length_(As, Bs).

same_length_([], []).
same_length_([_|As], [_|Bs]) :-
   same_length_(As, Bs).

查询:

?- L = [a|L], same_length(L, _).
   false.
?- same_length(L, [_|L]).
   false.
?- same_length([_], L).
   L = [_A].
?- same_length(L, M).
   L = [], M = []
;  L = [_A], M = [_B]
;  ... .

【讨论】:

  • 我喜欢subsumes_term([_|_], Cs0),确实值得编译成nonvar(Cs0), Cs0 = [_|_]
  • 并且您不使用Max ...
【解决方案2】:

更新的解决方案

这是我的解决方案:

same_length(A, A).
same_length([_|A], [_|B]) :- same_length(A, B).
    
?- same_length(L, [_|L]).
  L = [_1696|L]

我不确定它是否具有您正在寻找的所有属性。例如,如果你打电话

? - same_length(L, [1,2,3]).

然后它列出了许多答案,例如L = [_X, 2, 3],而不仅仅是 [_X, _Y, _Z]。但它是纯粹的,并且会为引用的查询产生正确的答案。

【讨论】:

  • same_length(L, [_|L]). 应该会失败,但您的版本会产生无限多的答案。
  • ?- same_length([1],[2]). true ; true, unexpected. 这会产生一个冗余解决方案。
  • 感谢您查看解决方案!我已经更新了它。现在,您的第二个示例没有多余的解决方案。对于第一个,它实际上不应该失败。 Prolog 在某种程度上支持无限列表。所以当我们得到一个解L = [_1696|L] 时,这意味着 L 是一个包含相同元素的无限列表,这是真的。至于数解是无限的,这并不理想,我同意。
  • 还有?- same_length([1],[1]). true ; true.
  • Prolog 在某种程度上支持无限列表。这不是真正的问题。主要问题是您的程序(有或没有无限列表)不会像原始程序一样终止。我希望这一点得到改善。此外,在原始程序中,没有任何空间可以容纳 L = [_|L] 这样的解决方案。它只是循环。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多