首页 文章

列表Prolog的每个元素的事实

提问于
浏览
2

我想在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 回答

  • 3

    我将对这个问题采取不同的方法 .

    我们希望找到满足作为“中间”值的标准的所有值,这个值被定义为大于列表中之前的所有值,并且小于之后的所有值 .

    将谓词 mid(L, M) 定义为含义 M 是"mid"的"mid"值:

    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”将全部连续聚集在一起,因此一旦找到“mid”,继续搜索是否随后遇到一个本身不是“mid”的元素是没有意义的 . 如果效率是目标,那么这些想法可以融入逻辑过程 .

    ADDENDUM

    由于@false提醒我 maplist ,上述谓词调用 less(X, T) 可以替换为 maplist(<(X), T) ,从而消除了上述实现中 less 的定义 .

  • 2

    这是一个使用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).
    

相关问题