列表Prolog的每个元素的事实

时间:2014-02-19 12:59:01

标签: prolog

我想在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中这样做,但我不知道如何迭代列表。

2 个答案:

答案 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),因为ML的“中间”值:

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的定义。