当你在调用
append
方法时,在参数中使用下划线
_
表示该参数是一个任意列表,「任意」的含义也包括长度任意。
例如:
?- append(_, Suffix, [a, b, c]).
Suffix = [a, b, c] ;
Suffix = [b, c] ;
Suffix = [c] ;
Suffix = [] ;
false.
这里的_
可以代表任何一个列表[]
、[a]
、[a, b]
、[a, b, c]
。但我不需要告诉你这一点,如果你给匿名变量_
指定一个适当的名称,Prolog就能告诉你这一点:
?- append(Prefix, Suffix, [a, b, c]).
Prefix = [],
Suffix = [a, b, c] ;
Prefix = [a],
Suffix = [b, c] ;
Prefix = [a, b],
Suffix = [c] ;
Prefix = [a, b, c],
Suffix = [] ;
false.
与之相反,[_]
这个术语不代表任意列表,而是代表确切只有一个元素的列表。这个元素用 _
表示,其本身是任意的。
例如:
?- append([_], Suffix, [a, b, c]).
Suffix = [b, c].
或者,再次使用适当的变量名称,以便我们可以看到绑定关系:
?- append([X], Suffix, [a, b, c]).
X = a,
Suffix = [b, c].
这里想要表达的是,从问题中提出的定义是:
listWithinList(X,Y):-append(_,Y2,Y), append(X,_,Y2).
这段话基本上是正确的。但是两个_
使用并不是每次"移除"一个元素,而是每次"移除" 任意数量的元素。因此你并不仅仅获得列表的中间部分:
?- listWithinList(Middle, [a, b, c, d, e]).
Middle = [] ;
Middle = [a] ;
Middle = [a, b] ;
Middle = [a, b, c] ;
Middle = [a, b, c, d] ;
Middle = [a, b, c, d, e] ;
Middle = [] ;
Middle = [b] ;
Middle = [b, c] ;
Middle = [b, c, d] ;
Middle = [b, c, d, e] ;
Middle = [] ;
Middle = [c] ;
Middle = [c, d] ;
Middle = [c, d, e] ;
Middle = [] ;
Middle = [d] ;
Middle = [d, e] ;
Middle = [] ;
Middle = [e] ;
Middle = [] ;
false.
如果我们想要从列表的开头和结尾“删除”仅有一个元素的列表,那么我们必须写成
[_]
:
listWithinList(X, Y) :-
append([_], Y2, Y),
append(X, [_], Y2).
现在它的行为是这样的:
?- listWithinList(Middle, [a, b, c, d, e]).
Middle = [b, c, d] ;
false.
此外,请注意
[_]
和
[_|_]
的区别。前者代表仅有
一个元素的列表。而后者表示拥有
一个或多个元素的列表。在这种情况下,您不希望“删除”超过一个元素,因此像其他答案建议的那样使用
[_|_]
是绝对荒谬的。
最后,Prolog可以为我们提供进一步简化:
?- append([X], Xs, Ys).
Ys = [X|Xs].
将一个只含有一个元素 [X]
和一个任意列表 Xs
连接在一起可以得到一个新的列表,我们也可以使用 [X | Xs]
来表示这个列表,而不需要使用 append
。因此,其中一个 append
调用是不必要的。我可能会这样写这个谓词:
list_middle(List, Middle) :-
append([_First | Middle], [_Last], List).
并像这样使用:
?- list_middle([a, b, c, d, e], Middle).
Middle = [b, c, d] ;
false.
或者像这样:
?- list_middle(List, [1, 2, 3]).
List = [_2658, 1, 2, 3, _2664].
pred(A,B):- append([[_],A,[_]],B)
。 - Will Ness