可以收緊你有相當多的如下:
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