【问题标题】:Fact for each element of a list Prolog列表 Prolog 中每个元素的事实
【发布时间】:2014-02-19 12:59:01
【问题描述】:

我想在 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).,结果将是一个元素列表。

对不起,如果我没有使用正确的 Prolog 术语。我将用顺序逻辑语言更具体地描述我想做什么,尽管这样思考并不是一个好主意。如果我们将谓词检查视为给定列表和列表元素的函数,则无论元素是否满足问题的条件,它都会返回真或假。现在我想解析列表的每个元素,并为每个元素调用函数检查。如果那会返回 true,那么我会将元素添加到另一个列表中,也就是结果。我想在 Prolog 中执行此操作,但我不知道如何迭代列表。

【问题讨论】:

  • 你的check 关系有三个参数,但你的check2 关系用两个参数调用它。您是否希望check 作为变量List2 返回一个仅包含一项的列表,即Elem
  • 你写的测试检查是否对所有元素都为真。你到底想要什么?不要认为在“Do this Do that”中更多地用“这意味着”来描述它
  • @alpha 我编辑了帖子,我忘记了一个论点。
  • @User 检查工作正常。我不提供任何进一步的信息,因为它的真正作用并不重要。
  • 现在我想做另一个谓词,给定一个列表,它对列表中的每个元素进行上述计算。针对什么列表?你的意思是,给定一个列表,你想在该列表的每个元素上针对完整的原始列表运行check?然后在check2 中,如果有的话,你想对check 的结果列表做什么?

标签: prolog


【解决方案1】:

这是一个使用 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)。我正在考虑尝试 DCG 方法,但没有成功。
  • 糟糕,我认为您的意思是 maplist(&gt;(M),Sm)maplist(&lt;(M),Gr)
【解决方案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([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(&lt;(X), T),消除了上面实现中less 的定义。

【讨论】:

  • 我找不到词来感谢你!非常感谢您的时间和精力
  • @Mario 没问题。用能很好地映射到 prolog 的逻辑语言表达问题对于找到解决方案大有帮助。
  • mids([2],[2]). 失败。但是左侧和右侧的所有元素都更小/更大。
  • @false,是的,这是设计使然。我不确定 OP 对极端情况有何意义。既然你提到它,一个元素应该被认为大于或小于空列表。我已经相应地更新了答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多