可以收紧你有相当多的如下:
delete_last(L, L1) :-
append(L1, [_], L).
delete_first([_|L], L).
% No need to check length of 1, since we only need to check
% if L = [X] in the caller, so we'll eliminate this predicate
%check_len(L) :-
% length(L, 1). % No need for an extra variable to check length is 1
% Clauses that yield false are not needed since clauses already fail if not true
% So you can just remove those
%
delete_both([X], X) :-
write('MidElement').
% Here you need to fix the logic in your main clause
% You are deleting the first element of the list, then the last element
% from that result and checking if the length is 1.
delete_both(L, X) :-
delete_first(L, L1), % Remove first and last elements from L
delete_last(L1, LT),
( LT = [X] % Check for length of 1
-> true
; delete_both(LT, X) % otherwise, X is result of delete_both(LT, X)
).
有了结果:
| ?- delete_both([a,b,c,d,e], X).
X = c
yes
| ?- delete_both([a,b,c,d,e,f], X).
no
一个DCG解决方案也是行之有效的位置:
% X is the middle if it is flanked by two sequences of the same length
%
middle(X) --> seq(N), [X], seq(N).
seq(0) --> [].
seq(N) --> [_], { N #= N1 + 1 }, seq(N1).
middle(List, X) :- phrase(middle(X), List).
有结果:
| ?- middle([a,b,c,d,e], X).
X = c ? ;
(1 ms) no
| ?- middle(L, a).
L = [a] ? ;
L = [_,a,_] ? ;
L = [_,_,a,_,_] ?
...
另一种可能的解决方案是使用SWI序言的
append/2
谓词,其中追加名单列表(假设你使用SWI):
middle(L, X) :-
same_length(Left, Right),
append([Left, [X], Right], L).
same_length([], []).
same_length([_|T1], [_|T2]) :- same_length(T1, T2).
在上述所有的解决方案,如果列表具有偶数个元素,谓词将失败。既然这就是你原来的解决方案,我认为这是必需的。如果偶数名单有特殊要求,则需要明确说明。
你是否支持所有大小的列表(偶数和奇数)?如果是这样,请看相关的问题“如何获得列表方案和序言的第一个,中间和最后一个元素?” (http://stackoverflow.com/questions/30112114/how-to-get-the-first-middle-and-last-element-of-a-list-scheme-and-prolog/30117040#30117040)和这个答案特别是http://stackoverflow.com/a/30117040/4609915。 HTH! – repeat