Flatten a list in Prolog

后端 未结 7 732
执笔经年
执笔经年 2020-11-27 08:00

I\'ve only been working with Prolog for a couple days. I understand some things but this is really confusing me.

I\'m suppose to write a function that takes a list

7条回答
  •  孤独总比滥情好
    2020-11-27 08:24

    You can maintain your lists open-ended, with both a pointer to its start, and an "ending hole ⁄ free pointer" (i.e. logvar) at its end, which you can then instantiate when the end is reached:

    flatten2( [], Z, Z):- !.                                        % ---> X
    flatten2( [Atom|ListTail], [Atom|X], Z) :-                      %      .
        \+is_list(Atom), !,                                         %      .
        flatten2( ListTail, X, Z).                                  %      Y
    flatten2( [List|ListTail], X, Z) :-                             %      .
        flatten2( List,     X, Y),       % from X to Y, and then    %      .
        flatten2( ListTail, Y, Z).       % from Y to Z              %      Z --->
    

    You then call it as

    flatten2( A, B):- flatten2( A, B, []).
    

    That way there's no need to use reverse anywhere. This technique is known as "difference lists", but it's much easier just to think about it as "open-ended lists" instead.


    update: This is much easier coded using the dcg syntax. Since it is unidirectional (the first argument must be fully ground), why not use cuts after all:

    flattn([]) --> [], !.
    flattn([A|T]) --> {\+is_list(A)}, [A], !, flattn(T).
    flattn([A|T]) --> flattn(A), flattn(T).
    

    Testing:

    16 ?- phrase(flattn([a,[b,c],[[d],[],[e]]]), [a, b, c, d, e]).
    true.
    
    17 ?- phrase(flattn([a,[b,c],[[d],[],[e]]]), R).
    R = [a, b, c, d, e].
    
    18 ?- phrase(flattn([a,[b,X],[[d],[],[e]]]), [a, b, c, d, e]).
    X = c.
    

    If the definition were fully declarative, the last one should've succeeded also with X=[c] ; X=[[],c] ; ... ; X=[[c]] ; ...; alas, it isn't.

    (edit2: simplified both versions, thanks to @mat's comments!)

提交回复
热议问题