简体   繁体   中英

nested lists in prolog

I have to separate this:

    [[[1,2,3,4]],[[1],[1,3],[1,2,3,4]],[[1,2,3,4]],[[1,2,3,4]]]

In something like this

    w1 = [1,2,3,4]
    w2 = [1],[1,3],[1,2,3,4]
    w3 = [1,2,3,4]
    w4 = [1,2,3,4]

Could someone help me?

It sounds like you need to walk a nested list of arbitrary depth (a tree, as it were), identify the flat lists it contains (eg, a list, each member of which is it itself a list), and return the list of flat lists that it has found.

We're going to use a helper predicate that uses a difference list (also called an open, or partial list).

A closed list is something like [a,b] , which is the data structure: .( a, .( b, [] ) ) or [a,b|[]] , where the list is terminated with [] . An difference list (or open list ) containing the two member a and b would look like [a,b|T] where T is an unbound variable. It is the same as .( a, .( b, T ) ) .

The utility of difference lists is that if you track its last element, which is unbound, you can keep appending to it, and then close it by unify that last element with [] once you're done.

So...

we have the primary predicate itself, extract/2 , which runs down the source list and invokes the helper on each one, building up the list of flat lists as it goes. When that source list is exhausted, the result list is closed:

extract( []     , [] ) .
extract( [X|Xs] , Ys ) :- extract(X,Ys,Y1), extract(Xs,Y1).

The helper, extract/3 isn't much more complicated. It just looks at what it was passed. If that is a

  • Non-list, it's flat
  • Flat list, it's flat
  • For any non-flat list, we
    • Recursively extract flat things from it head, and
    • If there's a non-empty tail, recursively extract flat things from that.
extract( X         , [X|Ys] , Ys ) :- \+ is_list(X), !.
extract( X         , [X|Ys] , Ys ) :- flat_list(X) , !.
extract( [X]       , Ys     , Y1 ) :- extract(X,Ys,Y1).
extract( [X,X1|Xs] , Ys     , Y2 ) :- extract(X,Ys,Y1), extract([X1|Xs],Y1,Y2) .

Finally we have to define what constitutes a "flat" list. That's pretty simple, too. A list if flat if none of its members are a list:

flat_list( []     ) .
flat_list( [X|_]  ) :- is_list(X), !, fail .
flat_list( [_|Xs] ) :- is_flat(Xs) .

Putting it all together, you get this:

extract( []     , [] ) .
extract( [X|Xs] , Ys ) :- extract(X,Ys,Y1), extract(Xs,Y1).

extract( X         , [X|Ys] , Ys ) :- \+ is_list(X), !.
extract( X         , [X|Ys] , Ys ) :- flat_list(X) , !.
extract( [X]       , Ys     , Y1 ) :- extract(X,Ys,Y1), !.
extract( [X|Xs] , Ys     , Y2 ) :- extract(X,Ys,Y1), extract(Xs,Y1,Y2) .

flat_list( []     ) .
flat_list( [X|_]  ) :- is_list(X), !, fail .
flat_list( [_|Xs] ) :- flat_list(Xs) .

You can fiddle with it here: https://swish.swi-prolog.org/p/extract-from-list-of-lists.pl

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM