【问题标题】:Prolog program to find equality of two lists in any orderProlog程序以任何顺序查找两个列表的相等性
【发布时间】:2019-02-01 04:08:32
【问题描述】:

我想编写一个 Prolog 程序来查找两个列表的相等性,其中元素的顺序
没关系。所以我写了以下内容:

del(_, [], []) .
del(X, [X|T], T).  
del(X, [H|T], [H|T1]) :-
   X \= H,
   del(X, T, T1).

member(X, [X|_]).  
member(X, [_|T]) :- 
   member(X, T).

equal([], []).  
equal([X], [X]).  
equal([H1|T], L2) :-
   member(H1, L2),
   del(H1, L2, L3),
   equal(T, L3).  

但是当我输入equal([1,2,3],X). 时,它不会显示X 的所有可能值。相反,程序挂在中间。可能是什么原因?

【问题讨论】:

  • 即确定两个集合的相等性

标签: list prolog any failure-slice


【解决方案1】:
isSubset([],_).
isSubset([H|T],Y):-
    member(H,Y),
    select(H,Y,Z),
    isSubset(T,Z).
equal(X,Y):-
    isSubset(X,Y),
    isSubset(Y,X).

【讨论】:

  • select/3 之前的 member/2 不需要。 equal/2 不能正常工作:它只给出一个解决方案,然后在重做时挂起:?- equal([1,2,3],X)。 X = [1, 2, 3] ;错误:由于内存不足,执行中止。因此投票否决答案。
【解决方案2】:

尝试使用谓词来检查其中一个集合是否是另一个集合的排列:

delete(X, [X|T], T).

delete(X, [H|T], [H|S]):-
    delete(X, T, S).


permutation([], []).

permutation([H|T], R):-
    permutation(T, X), delete(H, R, X).

(谓词取自http://www.dreamincode.net/code/snippet3411.htm

?- permutation([1,2,3],[3,1,2]).
true 

【讨论】:

  • 链接已失效。
【解决方案3】:

您观察到的未终止的实际原因是:以下子句不以任何方式、形状或形式限制 L2

等于([H1|T], L2) :- 成员(H1,L2), 德尔(H1,L2,L3), 等于(T,L3)。

所以您的查询?- equal([1,2,3], X). 意味着证明目标member(_, L2) 不会普遍终止。因此equal([1,2,3], X) 也不能普遍终止!

有关如何解释 Prolog 代码不终止的更多信息,请阅读 !


PS。从另一个角度来看终止问题,我们看到在这种情况下,不终止实际上是一个必然结果

为什么?因为您没有限制多重性的数量,这使得解决方案集的大小是无限的。该集合不能由有限数量的答案表示(前提是您不允许延迟目标)。

【讨论】:

    【解决方案4】:

    如果您不关心列表元素的多样性, 检查是否有足够的实例化 ground/1, 强制执行 iwhen/2, 并使用sort/2 消除重复项,如下所示:

    same_elements(As, Bs) :-
       iwhen(ground(As+Bs), (sort(As,Es),sort(Bs,Es))).
    

    SWI Prolog 8.0.0 的使用示例:

    ?- same_elements([a,c,c,b,a,c], [c,b,b​​,a])。 真的。 ?- same_elements([a,b,b,a], [b,a,b,e])。 错误的。 ?-same_elements([a,b,b,a], Xs)。 错误:参数没有充分实例化

    【讨论】:

      【解决方案5】:

      试试这个:

      equal([],[]).
      equal([Ha|Ta],[Hb|Tb]) :-
         Ha = Hb, lequal(Ta,Tb).
      

      【讨论】:

        【解决方案6】:

        怎么样:

        equal(X, Y) :-
            subtract(X, Y, []),
            subtract(Y, X, []).
        

        【讨论】:

          【解决方案7】:

          那么为什么equal([1,2,3], X) 不会在您的代码中普遍终止?

          让我们看一下您的代码的!什么是故障切片?这是标签信息:

          failure-slice 是通过添加一些目标false 获得的 Prolog 程序的片段。失败切片有助于定位纯单调 Prolog 程序普遍不终止的原因。它们还有助于为所需的推理数量提供一个下限。这是一个具体的 技术。

          创建失败切片:

          • 我们将<b>false</b>目标插入到程序中
          • 同时确保片段不会以上述目标终止。
          del(_, [], []) :- falsedel(X, [X|T], T) :- falsedel(X, [H|T], [H|T1]) :- false, dif(X, H), % 注意 OP 最初使用的是 `X \= H` 删除(X,T,T1)。 成员(X,[X|_])。 成员(X,[_|T]):- 成员(X,T)。 equal([], []) :- falseequal([X], [X]) :- false。 等于([H1|T],L2):- 成员(H1,L2),del(H1, L2, L3), 等于(T,L3)。 ?- 等于([1,2,3],_),false。 % 注意 `false` 是多余的... ** LOOPS ** % ... 如上 `equal/2` 不能成功。

          那么...上面的故障切片告诉我们什么?它说:

          • 使目标equal([1,2,3], X) 普遍终止...
          • ...我们必须更改至少一个剩余部分(那些没有划线)!

          【讨论】:

            【解决方案8】:

            我建议使用内置谓词msort/2,然后比较列表。在 SWI Prolog 上需要 O(nlogn) 时间,而简单地逐个元素检查未排序的列表需要 O(n2) 时间。

            lists_equal(List1, List2) :-
                msort(List1, Sorted1),
                msort(List2, Sorted2),
                Sorted1=Sorted2.
            

            这里,排序列表需要 O(nlogn) 时间,在 SWI Prolog 上比较它们需要 O(n) 时间,我不知道其他实现。

            【讨论】:

              【解决方案9】:

              简述

              equal([],[]).
              equal([H|T],[H|T1]):-equal(T,T1).
              

              【讨论】:

              • 如果列表包含不同顺序的相同项目,这将不起作用。
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2021-06-22
              • 1970-01-01
              • 1970-01-01
              • 2019-11-12
              相关资源
              最近更新 更多