【问题标题】:Get list of atoms by index from i to j in Prolog在Prolog中按索引从i到j获取原子列表
【发布时间】:2016-04-02 02:49:26
【问题描述】:

我想根据给定的 index_from i 到 index_to j 从原子列表中获取原子列表。我尝试了很多次,但它没有返回我的列表,而是一个“真”下面是我的代码,我错过了什么?如何获取我的输出列表而不是“真”。

% splitList(INPUT_LIST, INDEX_FROM, INDEX_TO, INDEX_FROM, OUTPUTLIST).
splitList(INPUT_LIST,INDEX_FROM,INDEX_TO, S,LIST) :-
    INPUT_LIST = INPUT_LIST,
    S = S,
    INDEX_FROM =:= INDEX_TO + 1,
    write(LIST),
    LIST = LIST.
splitList(INPUT_LIST,INDEX_FROM,INDEX_TO,S,LIST) :-
    INDEX_FROM < INDEX_TO + 1,
    nth0(INDEX_FROM, INPUT_LIST, ELEMENT),
    (  INDEX_FROM =:= S ->
    L = []
    ;   
    L = LIST
    ),
    IF is INDEX_FROM + 1,
    append([ELEMENT],L,NLIST),
    splitList(INPUT_LIST,IF,INDEX_TO,S,NLIST),
    !.

?- splitList(['TYPE_INT', 'IDENTIFIER', 'OPEN_P', 'TYPE_INT', 'IDENTIFIER', 'COMMA'],0,3,0,L).
?- true.

My atom list: ['TYPE_INT', 'IDENTIFIER', 'OPEN_P', 'TYPE_INT', 'IDENTIFIER', 'COMMA'],

if index_from is 1, index_to is 3, I am expecting a returned output_list:
['TYPE_INT', 'IDENTIFIER', 'OPEN_P', 'TYPE_INT'] instead of a 'true', 

在我的基本情况下,'write(LIST) 确实写入了预期的列表',知道吗?

【问题讨论】:

    标签: list split prolog


    【解决方案1】:

    您可以编写这样的谓词而不使用cut。想想你的谓词应该描述什么:一个列表,一些开始、结束和当前位置的索引,以及适合你的开始和结束索引的第一个列表的子列表。所以 list_indices_sublist 可能是个好名字。现在考虑一下您可以拥有哪些案例:

    如果当前位置和结束位置相同,则第一个列表的头部是最后一个在子列表中的:

    list_indices_sublist([X|_Xs],_Start,End,End,[X]).
    

    如果当前位置在开始位置和结束位置之间,则第一个列表的头部位于子列表中。对于两个列表的尾部,关系(=谓词)也必须成立(=递归):

    list_indices_sublist([X|Xs],Start,End,Pos,[X|Zs]) :-
        Pos #>= Start,
        Pos #< End,
        Nextpos #= Pos + 1,
        list_indices_sublist(Xs,Start,End,Nextpos,Zs).
    

    如果当前位置小于起始位置,则列表头不在子列表中。对于尾巴,同上:

    list_indices_sublist([X|Xs],Start,End,Pos,Zs) :-
        Pos #< Start,
        Nextpos #= Pos+1,
        list_indices_sublist(Xs,Start,End,Nextpos,Zs).
    

    您还可以考虑提供一个更简洁的界面,该界面隐藏了用于说明列表中当前位置的辅助变量。这样的谓词也将是适用于 list_indices_sublist/5 的所有三个规则的约束的好地方,例如开始索引必须小于或等于结束索引。我们称这个谓词为 list_sublist_from_to/4。把它们放在一起:

    :- use_module(library(clpfd)).
    
    
    list_sublist_from_to(L,S,Start,End) :-
        Start #=< End,
        list_indices_sublist(L,Start,End,1,S).
    
    list_indices_sublist([X|_Xs],_Start,End,End,[X]).
    list_indices_sublist([X|Xs],Start,End,Pos,[X|Zs]) :-
        Pos #>= Start,
        Pos #< End,
        Nextpos #= Pos + 1,
        list_indices_sublist(Xs,Start,End,Nextpos,Zs).
    list_indices_sublist([X|Xs],Start,End,Pos,Zs) :-
        Pos #< Start,
        Nextpos #= Pos+1,
        list_indices_sublist(Xs,Start,End,Nextpos,Zs).
    

    关于您提供的示例:您的意思是 1 到 4,对吗?

    ?- list_sublist_from_to(['TYPE_INT', 'IDENTIFIER', 'OPEN_P', 'TYPE_INT', 'IDENTIFIER', 'COMMA'] ,L,1,4).
    L = ['TYPE_INT','IDENTIFIER','OPEN_P','TYPE_INT'] ? ;
    no
    

    或 1 到 3 以及子列表中包含 3 个元素的答案:

    list_sublist_from_to(['TYPE_INT', 'IDENTIFIER', 'OPEN_P', 'TYPE_INT', 'IDENTIFIER', 'COMMA'] ,L,1,3).
    L = ['TYPE_INT','IDENTIFIER','OPEN_P'] ? ;
    no 
    

    注意:如果您想从 0 而不是 1 开始计算列表位置,只需将 list_sublist_from_to/4 的第二个目标中的 1 更改为 0

    【讨论】:

      【解决方案2】:

      首先,你应该注意到Prolog不是基于赋值,而是基于统一。然后,例如,

      INPUT_LIST = INPUT_LIST,
      

      是一个重言式(将 same 术语与其自身统一,始终为真)。您可以安全地删除它们。

      其次,您的代码有一个附加参数S,它没有明确的作用。可能是您尝试实现的残余细节,但它应该真的被“隐藏”,例如:

      % splitList(INPUT_LIST, INDEX_FROM, INDEX_TO, OUTPUTLIST).
      splitList(INPUT_LIST, INDEX_FROM, INDEX_TO, LIST) :-
        splitList(INPUT_LIST, INDEX_FROM, INDEX_TO, 0, LIST).
      

      第三,在谓词的最后一个子句结尾处的删减是完全没有用的,因为所有的替代方案都已经尝试过了——并且成功了。没有什么可剪的……

      第四,既然你使用内置的 nth0/3,那么请注意,一个更简单的实现可能是

      splitList(INPUT_LIST,INDEX_FROM,INDEX_TO, LIST) :-
        findall(E, (between(INDEX_FROM,INDEX_TO,I),nth0(I,INPUT_LIST,E)), LIST).
      
      ?- splitList(['TYPE_INT', 'IDENTIFIER', 'OPEN_P', 'TYPE_INT', 'IDENTIFIER', 'COMMA'],0,3,L).
      L = ['TYPE_INT', 'IDENTIFIER', 'OPEN_P', 'TYPE_INT'].
      

      但让我们尝试更正您的代码。可能是

      splitList(INPUT_LIST,INDEX_FROM,INDEX_TO, LIST) :-
        splitList(INPUT_LIST,INDEX_FROM,INDEX_TO, 0, LIST).
      
      splitList(INPUT_LIST,INDEX_FROM,INDEX_TO, S,LIST) :-
        S < INDEX_FROM,
        S1 is S+1,
        splitList(INPUT_LIST,INDEX_FROM,INDEX_TO, S1,LIST).
      splitList(INPUT_LIST,INDEX_FROM,INDEX_TO, S,[ELEMENT|LIST]) :-
        S >= INDEX_FROM, S =< INDEX_TO,
        nth0(S, INPUT_LIST, ELEMENT),
        S1 is S+1,
        splitList(INPUT_LIST,INDEX_FROM,INDEX_TO, S1,LIST).
      splitList(_INPUT_LIST,_INDEX_FROM,INDEX_TO, S,[]) :-
        S > INDEX_TO.
      

      并且会得到与上面列出的基于 findall/3 的单行类似的结果。请注意,ELEMENT 不是使用 append/3,而是“consed”到“output”参数中。看看你是否能发现这段代码固有的问题,具体来说,试着理解为什么

      ?- splitList(['TYPE_INT', 'IDENTIFIER', 'OPEN_P', 'TYPE_INT', 'IDENTIFIER', 'COMMA'],0,10,L).
      false.
      

      【讨论】:

        猜你喜欢
        • 2014-11-25
        • 1970-01-01
        • 2023-04-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-07-24
        • 1970-01-01
        • 2021-11-06
        相关资源
        最近更新 更多