Prolog添加到列表的深度版本谓词



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

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,这是列表吗?

也许您可以在第一位"捕获"列表,添加第一个子句作为

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

这是一个解决方案。切割是必要的,否则它会回溯并在以后给出错误的解决方案。我曾尝试使用旧的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检查它是否是列表,然后调用建议的谓词。

我会从告诉我一个术语是否为列表的东西开始,大致如下:

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

然后,它只是在现有谓词中添加另一个case,类似于以下内容:

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
  .                               %

最新更新