【问题标题】:Prolog deep version predicate of adding to a list添加到列表的 Prolog 深度版本谓词
【发布时间】:2014-10-14 00:21:40
【问题描述】:

我必须编写一个深度版本的谓词,为列表中的每个数字元素添加一个数字,我已经完成了非深度版本:

addnum(N,T,Y)

这给出了类似的东西:

e.g. ?-addnum(7,[n,3,1,g,2],X).
X=[n,10,8,g,9]

但我现在想创建一个深度版本的 addnum 应该这样做:

e.g. ?-addnumdeep(7,[n,[[3]],q,4,c(5),66],C).
X=[n,[[10]],q,11,c(5),73]

谁能给我一些建议?我从这个开始:

islist([]).
islist([A|B]) :- islist(B).
addnumdeep(C,[],[]).
addnumdeep(C,[Y|Z],[G|M]):-islist(Z),addnum(C,Y,[G,M]),addnumdeep(C,Z,M).

但我不认为我的逻辑是正确的。我在考虑检查尾部是否是一个列表,然后在头部运行 addnum,然后在尾部的其余部分运行 addnumdeep,这是一个列表?

【问题讨论】:

  • 可能会内置一个is_list,具体取决于您的平台。看看可能出现的情况,现在有三个处于最深的回避级别,所以你可能需要一个新的add 谓词(我指的是你之前的问题)。
  • 如果你有[Y|Z],你不需要检查Z是否是一个列表,因为它一定已经是因为[Y|Z]是一个带有尾部列表Z的列表。您需要检查Y 是否是一个列表,因为它可能是也可能不是。如果是,则 [Y|Z] 是一个列表,其中包含列表 Y 作为其第一个元素。
  • @lurker 实际上,顺便说一句,符号[Head|Tail] 并不一定意味着Tail 是一个列表。例如,[Y|Z] = [a|b] 为真(使用绑定 Y = a, Z = b)。
  • 检查Y是否是一个列表,如果是,调用addnumdeep,如果不是,调用add_if_number
  • @PauloMoura 是的,感谢您指出这一点。我以前在 Prolog 中玩过非列表尾巴。我的评论有点草率,因为当我写评论时,我的脑海里有这个。在这种情况下,我认为可以安全地假设它打算/预期是一个列表尾部。即便如此,这里是否有必要明确检查尾部确实是一个列表,这一点尚不清楚。

标签: prolog predicate


【解决方案1】:

也许您可以首先“抓住”列表,添加为 first 子句

addnum(N,[T|Ts],[Y|Ys]) :- addnum(N,T,Y),addnum(N,Ts,Ys).

【讨论】:

    【解决方案2】:

    这是一种解决方案。削减是必要的,否则它会在以后回溯并给出错误的解决方案。我曾尝试使用旧的 addnum 谓词,但您不知道之后是否必须更深入,所以只有当您有 addnum_3levels_deep 谓词时才可行,即使那样使用它也会更清楚解决方案并计算深度。

    addnumdeep(N,[X|Y],[G|H]):-
      !, % cut if it is a nonempty list 
      (number(X)->
       G is N + X;
      addnumdeep(N,X,G)), % recurse into head
      addnumdeep(N,Y,H).  % recurse into tail
    
    addnumdeep(_,A,A).
    

    请注意,这也允许addnumdeep(7,3,3)。如果您希望它是addnumdeep(7.3.10),则必须提取括号中的条件:

    addnumdeep(N,[X|Y],[G|H]):-
      !, % cut if it is a nonempty list
      addnumdeep(N,X,G),
      addnumdeep(N,Y,H).
    
    addnumdeep(N,X,Y):-
      number(X),!, % cut if it is a number.
      Y is N+X.
    
    addnumdeep(_,A,A).
    

    这个解决方案更好,因为它突出了您可能遇到的三种基本情况: 它要么是一个列表,然后是资源,要么是一个数字,对于其他所有内容,只需将其放入结果列表的尾部(这也处理空列表的情况)。另一方面,你需要为这个解决方案使用红色切割,所以它可能会被一些纯粹主义者所反对。

    如果你不想要红色切割,你可以用

    替换最后一个子句

    addnumdeep(_,A,A):- !, \+ number(A), \+ A = [_|_].

    如果您不希望允许使用非列表,您可以先检查 is_list 是否是列表,然后调用建议的谓词。

    【讨论】:

      【解决方案3】:

      我会从告诉我一个术语是否类似于列表的东西开始,类似于以下内容:

      is_list_like( X     ) :- var(X) , ! , fail .
      is_list_like( []    ) .
      is_list_like( [_|_] ) .
      

      然后它只是在您现有的谓词中添加另一个案例,如下所示:

      add_num( _ , [] , [] ) .          % empty list? all done!
      add_num( N , [X|Xs] , [Y|Ys] ) :- % otherwise...
        number(X) ,                     % - X is numeric?
        Y is X + N ,                    % - increment X and add to result list
        add_num( N , Xs , Ys )          % - recurse down
        .                               %
      add_num( N , [X|Xs] , [Y|Ys] ) :- % otherwise...
        is_list_like( X ) ,             % - X seems to be a list?
        ! ,
        add_num( N , X , Y ) ,          % - recurse down on the sublist
        add_num( N , Xs , Ys )          % - then recurse down on the remainder
        .                               %
      add_num( N , [X|XS] , [Y|Ys] ) :- % otherwise (X is unbound, non-numeric and non-listlike
        X = Y ,                         % - add to result list
        add_num( N , Xs , Ys )          % - recurse down
        .                               %
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-09-29
        • 2017-08-14
        • 2018-11-17
        相关资源
        最近更新 更多