【问题标题】:create circled List in Prolog在 Prolog 中创建带圆圈的列表
【发布时间】:2014-06-10 13:53:19
【问题描述】:

我正在尝试在 Prolog 中创建这个函数:

% Signature: circleList(L1, L2)/2
% Purpose: L2 is a "circled" L1 list.
% Precondition: L1 is fully instantiated.
% Examples:
% ?- circleList([2, 3, 4, 5], X).
% X = [2, 3, 4, 5];
% X = [3, 4, 5, 2];
% X = [4, 5, 2, 3];
% X = [5, 2, 3, 4];
% false.

所以我这样做了:

circleList([],[]).
circleList(X,X).
circleList([H|T],R):- append(T,[H],S), circleList(S,R).

但输出是这样的:

X = [2, 3, 4, 5] ;
X = [3, 4, 5, 2] ;
X = [4, 5, 2, 3] ;
X = [5, 2, 3, 4] ;
X = [2, 3, 4, 5] ;
X = [3, 4, 5, 2] ;
X = [4, 5, 2, 3] ;
X = [5, 2, 3, 4] ;
X = [2, 3, 4, 5] ;
X = [3, 4, 5, 2] 
and so on...

这很好,但我想在我第一次完成所有可能性后让它停止。

我能做什么?

【问题讨论】:

    标签: list prolog failure-slice


    【解决方案1】:

    您的谓词需要另一个参数。一种选择是使用列表中的元素,直到剩下 []

    circleList([Head|Tail],CL):-
        circleList(Tail,[Head],CL).
    
    circleList([],L,L).
    circleList([Head|Tail], Rest, CL):-
        append(Rest, [Head], NewRest),
        circleList(Tail, NewRest, CL).
    circleList([Head|Tail], Rest, CL):-
        append([Head|Tail], Rest,CL).
    

    我看到的另一个选项是使用length/2 将深度限制为列表的大小。

    circleList([],[]).
    circleList(List,CL):-
        length(List, N),
        circleList(List,N,CL).
    
    circleList(_,0,_):-!, fail.
    circleList(List,_,List).
    circleList([Head|Tail], N, CL):-
        append(Tail, [Head], NewList),
        N1 is N - 1,
        circleList(NewList, N1, CL).
    

    【讨论】:

      【解决方案2】:

      你可以简单地用不同的方式表述问题:

      rotatelist([], []).
      rotatelist(Xs, Ys) :-
         Xs = [_|_],
         Ys = [_|_],
         same_length(Xs, Ys), % avoid non-termination
         Bs = [_|_],          % avoid redundant answers
         append(As,Bs,Xs),
         append(Bs,As,Ys).
      
      same_length([], []).
      same_length([_E|Es], [_F|Fs]) :-
         same_length(Es, Fs).
      

      但如果你的意思是明确停止;好吧,这很容易被证明是不正确的。事实上,我看不出在这里如何使用剪切的自然方式。

      但是,您可以像这样限制递归的数量:

      circleList2(Xs, Ys) :-
         same_length(Xs, Ys),
         circleList2(Xs, Ys, Xs).
      
      circleList2(X,X, _).
      circleList2([H|T],R, [_|L]):-
         L = [_|_],
         append(T,[H],S),
         circleList2(S,R, L).
      

      所以这本质上是您的程序,带有一个用于限制递归次数的附加参数。以这种方式限制递归通常用于实现所谓的迭代深化算法。然而,在这种情况下,我们只有一个深度界限。不需要额外的迭代。

      【讨论】:

      • 我不能限制它,我不能用 3 个变量创建一个谓词,除非它像一个“帮助函数”。这是我关于使用 Prolog 进行关系逻辑编程基础知识的作业,所以我需要一个更好的解释
      • @kitsuneFox:为什么不能限制? same_length/2 和 circleList2/3 是辅助谓词。
      • @TudorBerariu:因为 circleList(L,[1,2]) 的循环会为 circleList([1,2],L) 提供冗余解决方案。
      • 目标append(A, B, L). 与两个未绑定变量AB 满足所有列表AB 的连接得到结果L。 (例如?- append(A,B,[a,b,c]). A = [], B = [a, b, c] ; A = [a], B = [b, c] ; A = [a, b], B = [c] ; A = [a, b, c], B = [] ; false.
      【解决方案3】:

      这是一个更简单的解决方案,但终止属性要弱得多。另一方面,您说第一个参数是“完全实例化的”。您能否快速为要“完全实例化”的参数生成测试?我假设不是。正是由于这个原因,这样的假设导致了如此多的错误。首先,程序员只是假设参数将被“完全实例化”,然后他们忘记了他们的假设......

      circleList3(Xs, Ys) :-
         append(As, Bs, Xs),
         append(Bs, As, Ys),
         ( As = [] ; As = [_|_], Bs = [_|_] ).
      

      此版本现在不再终止 circleList3(Xs, [])。要了解为什么会这样,我将使用,即在程序中添加false。如果剩下的部分仍然没有终止,那么一个问题在于可见部分。

      ?- circleList3(Xs, []), false。
      /* 循环 */
      
      circleList3(Xs, Ys) :-
         附加(As,Bs,Xs),假,
         追加(Bs, As, Ys),
         ( As = [] ; As = [_|_], Bs = [_|_] )

      这个失败切片不会终止,因为第一个目标是用 3 个未实例化的参数调用的。获得此终止的唯一帮助是 Ys,但没有人对此感兴趣!

      我们现在可以交换两个目标append/3 使这个片段终止,但是,其他查询不会终止...

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-04-25
        • 2011-12-18
        • 1970-01-01
        • 2015-05-18
        • 1970-01-01
        • 1970-01-01
        • 2019-03-19
        • 1970-01-01
        相关资源
        最近更新 更多