【问题标题】:Fill list in SWI-Prolog在 SWI-Prolog 中填写列表
【发布时间】:2011-07-22 16:00:46
【问题描述】:

我正在尝试用数字 1、2、3、...、N 填充给定长度 N 的列表。

我认为可以这样做:

create_list(N,L) :-
    length(L,N),
    forall(between(1,N,X), nth1(X,L,X)).

但是,这似乎不起作用。谁能说我做错了什么?

【问题讨论】:

    标签: list prolog


    【解决方案1】:

    第一件事:使用

    :- use_module(library(clpfd)).
    

    在下面我介绍zs_between_and/3,它(与我之前的答案相比)提供了更多功能。

    首先,让我们先定义一些辅助谓词!

    equidistant_stride([]    ,_).
    equidistant_stride([Z|Zs],D) :-
       equidistant_prev_stride(Zs,Z,D).
    
    equidistant_prev_stride([]     ,_ ,_).     % internal predicate
    equidistant_prev_stride([Z1|Zs],Z0,D) :-
       Z1 #= Z0+D,
       equidistant_prev_stride(Zs,Z1,D).
    

    让我们运行几个查询来获取equidistant_stride/2 的图片:

    ?- Zs = [_,_,_], equidistant_stride(Zs,D).
    Zs = [_A,_B,_C], _A+D#=_B, _B+D#=_C.
    
    ?- Zs = [1,_,_], equidistant_stride(Zs,D).
    Zs = [1,_B,_C], _B+D#=_C, 1+D#=_B.
    
    ?- Zs = [1,_,_], equidistant_stride(Zs,10).
    Zs = [1,11,21].
    

    到目前为止,一切都很好......继续实际的“填充列表”谓词zs_between_and/3

    zs_between_and([Z0|Zs],Z0,Z1) :-
       Step in -1..1,
       Z0 #= Z1 #<==> Step #=  0,
       Z0 #< Z1 #<==> Step #=  1,
       Z0 #> Z1 #<==> Step #= -1,
       N #= abs(Z1-Z0),    
       (  fd_size(N,sup)
       -> true
       ;  labeling([enum,up],[N])
       ),
       length(Zs,N),
       labeling([enum,down],[Step]),
       equidistant_prev_stride(Zs,Z0,Step).
    

    有点巴洛克风格,我必须承认...

    让我们看看获得了哪些功能——与我的previous answer相比!

    ?- zs_between_and(Zs,1,4).      % ascending  consecutive integers
    Zs = [1,2,3,4].                 % (succeeds deterministically)
    
    ?- zs_between_and(Zs,3,1).      % descending consecutive integers (NEW)
    Zs = [3,2,1].                   % (succeeds deterministically)
    
    ?- zs_between_and(Zs,L,10).     % enumerates fairly
      L = 10, Zs =       [10]       % both ascending and descenting (NEW)
    ; L =  9, Zs =     [9,10]
    ; L = 11, Zs =    [11,10]
    ; L =  8, Zs =   [8,9,10]
    ; L = 12, Zs = [12,11,10]
    ; L =  7, Zs = [7,8,9,10]
    ...
    
    ?- L in 1..3, zs_between_and(Zs,L,6).
      L = 3, Zs =     [3,4,5,6]
    ; L = 2, Zs =   [2,3,4,5,6]
    ; L = 1, Zs = [1,2,3,4,5,6].
    

    想要更多?我们开始吧!

    ?- zs_between_and([1,2,3],From,To).
      From = 1, To = 3
    ; false.
    
    ?- zs_between_and([A,2,C],From,To).
      A = 1, From = 1, C = 3, To = 3    % ascending
    ; A = 3, From = 3, C = 1, To = 1.   % descending
    

    【讨论】:

    • 不错的解决方案,+1! equidistant_prev_stride/3equidistant_stride_(D, Z1, Z0, Z1) :- Z1 #= Z0 + D. 的折叠,使用 equidistant_stride/2 中的目标:foldl(equidistant_stride_(D), Zs, Z, _)
    • @mat。 Thx 4 替代实现!我也喜欢这个名字。
    • 是的,我确实阅读过旧答案并给他们点赞!
    【解决方案2】:

    我现在没有可用的 prolog 解释器,但也没有...

      isListTo(N, L) :- reverse(R, L), isListFrom(N, R).
      isListFrom(0, []).
      isListFrom(N, [H|T]) :- M is N - 1, N is H, isListFrom(M, T).
    

    reverse 可以通过使用例如http://www.webeks.net/prolog/prolog-reverse-list-function.html

    所以追踪 isListTo(5, [1, 2, 3, 4, 5])...

      isListTo(5, [1, 2, 3, 4, 5])
      <=> isListFrom(5, [5, 4, 3, 2, 1])
      <=> 5 is 5 and isListFrom(4, [4, 3, 2, 1])
      <=> 4 is 4 and isListFrom(3, [3, 2, 1])
      <=> 3 is 3 and isListFrom(2, [2, 1])
      <=> 2 is 2 and isListFrom(1, [1])
      <=> 1 is 1 and isListFrom(0, [])
      QED
    

    由于 PROLOG 不仅会评估真相,还会找到令人满意的解决方案,所以这应该有效。我知道这是一种与您正在尝试的方法截然不同的方法,如果您的问题是专门关于在 PROLOG 中执行循环的问题(如果是这种情况,也许重新标记问题?)。

    【讨论】:

      【解决方案3】:

      这是一个使用的谓词zs_from_to/3逻辑纯实现:

      :- use_module(library(clpfd)).
      
      zs_from_to([],I0,I) :-
         I0 #> I.
      zs_from_to([I0|Is],I0,I) :- 
         I0 #=< I,
         I1 #= I0 + 1,
         zs_from_to(Is,I1,I).
      

      让我们使用它!首先,一些地面查询

      ?- zs_from_to([1,2,3],1,3)。 真的。 ?- zs_from_to([1,2,3],1,4)。 错误

      接下来,一些更一般的查询

      ?- zs_from_to(Zs,1,7).
        Zs = [1,2,3,4,5,6,7]
      ; false.
      
      ?- zs_from_to([1,2,3],From,To).
      From = 1, To = 3.
      

      现在,让我们进行一些更一般的查询

      ?- zs_from_to(Zs,From,2).
        Zs =            [], From in 3..sup
      ; Zs =           [2], From =  2
      ; Zs =         [1,2], From =  1
      ; Zs =       [0,1,2], From =  0
      ; Zs =    [-1,0,1,2], From = -1
      ; Zs = [-2,-1,0,1,2], From = -2
      ...
      
      ?- zs_from_to(Zs,0,To).
        Zs = [],          To in inf.. -1
      ; Zs = [0],         To = 0
      ; Zs = [0,1],       To = 1
      ; Zs = [0,1,2],     To = 2
      ; Zs = [0,1,2,3],   To = 3
      ; Zs = [0,1,2,3,4], To = 4
      ...
      

      对于最一般的查询,我们得到什么答案?

      ?- zs_from_to(Xs,I,J).
        Xs = [],        J#=<I+ -1
      ; Xs = [I],       I+1#=_A, J#>=I, J#=<_A+ -1
      ; Xs = [I,_A],    I+1#=_A, J#>=I, _A+1#=_B, J#>=_A, J#=<_B+ -1
      ; Xs = [I,_A,_B], I+1#=_A, J#>=I, _A+1#=_B, J#>=_A, _B+1#=_C, J#>=_B, J#=<_C+ -1
      ...
      

      编辑 2015-06-07

      为了改进zs_from_to/3 的上述实现,让我们做两件事:

      1. 尝试提高实施的确定性。
      2. 提取一个更通用的高阶习语,并在其上实现zs_from_to/3

      引入元谓词init0/3init1/3

      :- meta_predicate init0(2,?,?).
      :- meta_predicate init1(2,?,?).
      init0(P_2,Expr,Xs) :- N is Expr, length(Xs,N), init_aux(Xs,P_2,0).
      
      init1(P_2,Expr,Xs) :- N is Expr, length(Xs,N), init_aux(Xs,P_2,1).
      
      :- meta_predicate init_aux(?,2,+).  % internal auxiliary predicate
      init_aux([]    , _ ,_ ).
      init_aux([Z|Zs],P_2,I0) :-
         call(P_2,I0,Z),
         I1 is I0+1,
         init_aux(Zs,P_2,I1).
      

      让我们看看init0/3init1/3 的实际效果!

      ?- 初始化0(=,5,Zs)。 % ?- numlist(0,4,Xs),maplist(=,Xs,Zs)。 Zs = [0,1,2,3,4]。 ?- 初始化1(=,5,Zs)。 % ?- numlist(1,5,Xs),maplist(=,Xs,Zs)。 Zs = [1,2,3,4,5]。

      好的,我们从这里去哪里?考虑以下查询:

      ?- init0(plus(10),5,Zs)。 % ?- numlist(0,4,Xs),maplist(plus(10),Xs,Zs)。 Zs = [10,11,12,13,14]。

      快完成了!综上所述,我们这样定义zs_from_to/2

      z_z_sum(A,B,C) :- C #= A+B.
      
      zs_from_to(Zs,I0,I) :-
         N #= I-I0+1,
         init0(z_z_sum(I0),N,Zs).
      

      最后,让我们看看确定性是否有所改进!

      ?- zs_from_to(Zs,1,7).
      Zs = [1,2,3,4,5,6,7].          % succeeds deterministically
      

      【讨论】:

      • var(P_2) 检查的意义何在?使用适当的元谓词声明,它永远不会成功,如果成功,它可能有点为时过早。
      【解决方案4】:

      如果我理解正确,内置谓词 numlist/3 就可以了。 http://www.swi-prolog.org/pldoc/man?predicate=numlist/3

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-09-08
        • 1970-01-01
        • 2012-01-04
        • 1970-01-01
        • 1970-01-01
        • 2014-05-09
        相关资源
        最近更新 更多