我想在Prolog中解决这个问题。我想给出一个自然数列表,以找到列表中满足这个条件的所有元素:
All elements on the left of it are smaller than it and all the elements on the right of it are larger than it.
例如,提供一个列表[3,2,4,1,5,7,8,9,10,8]
,答案为5,7
到目前为止,我已经设法使这个函数给定一个列表元素,如果元素满足上述条件,则返回true或false。
check(Elem, List) :-
seperate(Elem, List, List1, List2),
lesser(Elem, List1, X1),
bigger(Elem, List2, X2),
size(X1, L1),
size(X2, L2),
size(List, L3),
match(L1, L2, L3),
现在我想创建另一个给定列表的谓词,它为列表的每个元素执行上述计算。由于多个元素可能满足它,我想创建另一个列表,其中包含满足问题的所有元素。
问题类似于?-predicate_name([[3,2,4,1,5,7,8,9,10,8],N).
,结果将是元素列表。
Sry如果我没有使用Prolog的正确条款。我将用顺序逻辑语言描述我想要做的更具体,尽管这样思考并不是一个好主意。如果我们将谓词检查视为给定列表和列表元素的函数,则无论元素是否满足问题条件,它都将返回true或false。现在我想解析列表中的每个元素,并为每个元素调用函数检查。如果那将返回true,那么我将在另一个列表a.k.a结果中添加该元素。我想在Prolog中这样做,但我不知道如何迭代列表。
答案 0 :(得分:3)
这是一个使用DCG的版本,假设我们想要进行算术比较。
list_mid(L, M) :-
phrase(mid(M), L).
mid(M) -->
seq(Sm),
[M],
{maplist(>(M),Sm)},
seq(Gr),
{maplist(<(M),Gr)}.
seq([]) -->
[].
seq([E|Es]) -->
[E],
seq(Es).
通常不值得进一步优化。第一个seq(Sm)
和后续maplist/2
可能会合并在一起。这有点棘手,因为必须单独处理Sm = []
和Sm = [_|_]
的情况。
mid(M) -->
( [M]
| max(Mx),
[M],
{Mx < M}
),
min(M).
max(M) -->
[E],
maxi(E, M).
maxi(E, E) -->
[].
maxi(E, M) -->
[F],
{G is max(F,E)},
maxi(G, M).
min(_) -->
[].
min(M) -->
[E],
{M < E},
min(M).
答案 1 :(得分:2)
我将对问题采取不同的方法。
我们希望找到符合“中间”值标准的所有值,这个值定义为大于列表中所有值之前的值,并且小于之后的所有值。
定义谓词mid(L, M)
,因为M
是L
的“中间”值:
mid([X|T], X) :- % The first element of a list is a "mid" if...
less(X, T). % it is less than the rest of the list
mid([X|T], M) :- % M is a "mid" of [X|T] if...
mid(T, X, M). % M is a "mid" > X
% (NOTE: first element is not a "mid" by definition)
mid([X|T], LastM, X) :- % X is a "mid" > Y if...
X > LastM, % X > the last "mid"
less(X, T). % X < the rest of the list, T
mid([X|T], LastM, M) :- % Also, M is a "mid" if...
Z is max(X, LastM), % Z is the larger of X and the last "mid"
mid(T, Z, M). % M is the "mid" of T which is > Z
less(X, [Y|T]) :- % X is less than the list [Y|T] if...
X < Y, % X < Y, and
less(X, T). % X < the tail, T
less(_, []). % An element is always less than the empty list
每个查询都会找到下一个“mid”:
| ?- mid([3,2,4,1,5,7,8,9,10,8], M).
M = 5 ? ;
M = 7 ? ;
no
然后可以使用findall
mids(L, Ms) :-
findall(M, mid(L, M), Ns).
| ?- mids([3,2,4,1,5,7,8,9,10,8], Ms).
Ms = [5,7]
yes
| ?- mids([2], L).
L = [2]
(1 ms) yes
这可能不是计算效率最高的解决方案,因为它没有利用“mids”的几个属性。例如,“mids”将全部连续聚集在一起,因此一旦找到“mid”,继续搜索是否随后遇到一个本身不是“mid”的元素是没有意义的。如果效率是目标,那么这些想法可以融入逻辑过程。
<强>附录强>
如果信用@false提醒我maplist
,则上述谓词调用less(X, T)
可以替换为maplist(<(X), T)
,从而取消上述实现中less
的定义。