嗯...首先,Prolog 没有“功能”:它有 谓词。
如果我理解您的问题陈述,您想“从列表中删除连续元素”,我理解为“将相同元素的运行折叠为单个值”,因此列表如下:
[a,b,b,b,,c,c,d,e,e,e,e]
简化为
[a,b,c,d,e]
假设是这种情况,您不需要(或不想要)append/3。一般的方案是
- 递归到列表末尾,然后
- 当您弹出调用堆栈时,您反复添加或省略
当前项,基于返回列表的头部
像这样:
remove( [] , [] ) .
remove( [X|Xs] , Ys ) :- remove(Xs,Ts), try_add(X,Ts,Ys) .
try_add/3 负责决定是否在返回的列表中添加/添加一个项目。它也是微不足道的:
- 如果返回的列表为空,则在其前面添加候选
X。
- 如果返回列表非空,则用返回列表的头部测试候选
X:
- 如果它们是可统一的,则省略候选
X,
- 否则,将候选
X 添加到返回的列表中
try_add( X , [] , [X] ) .
try_add( X , [T|Ts] , [T|Ts] ) :- X = T.
try_add( X , [T|Ts] , [X,T|Ts] ) :- X \= T.
综合起来,你会得到:
remove( [] , [] ) .
remove( [X|Xs] , Ys ) :- remove(Xs,Ts), try_add(X,Ts,Ys) .
try_add( X , [] , [X] ) .
try_add( X , [T|Ts] , [T|Ts] ) :- X = T.
try_add( X , [T|Ts] , [X,T|Ts] ) :- X \= T.
这在 O(n) 时间和空间中运行。它的缺点是它不是尾递归的,这意味着如果给定一个足够长的列表,它会因堆栈溢出而使您的程序崩溃。
另一种尾递归方法——在 O(n) 时间和 O(1) 空间中运行——是这样的:
remove( [] , [] ) .
remove( [X|Xs] , Ys ) :- remove(Xs, [X], Ts ), reverse(Ts,Ys) .
remove( [] , Ys , Ys ) .
remove( [X|Xs] , [T|Ts] , Ys ) :- X = T , remove( Xs , [X|Ts] , Ys ) .
remove( [X|Xs] , [T|Ts] , Ys ) :- X \= T , remove( Xs ,[X,T|Ts] , Ys ) .
它的缺点是它以相反的顺序构建返回列表,因此需要通过reverse/2 进行另一次遍历才能将事物以正确的顺序放回。