Reversing a list

2019-08-04 01:02发布

问题:

I need help reversing a list.

fun(a, [b, d]).
fun(b, [c]).
fun(c, []).
fun(d, [e]).
fun(e, [f]).
fun(f, [g]).
fun(g, []).

xyz(X, Y):- 
    fun(X, Z) -> findall([A|B], (member(A, Z), xyz(A, B)), L),
    flatten(L, F), sort(F, Y); Y = [].

The query xyz(a,X). gives me X = [b,c,d,e,f,g]. However, I would like it to give me X = [g,f,e,d,c,b].

I have tried different attempts at reversing the list, but I am not having any luck.

I have tried adding an additional predicate right after this, but it didn't work either:

xyz2(X,Y):-
    xyz(X,Y),
    reverse(Y,Z),
    Z\=0.

Credit goes to CapelliC for the approach to the implementation above found at my other post here. Recursion in PROLOG?

回答1:

You can avoid some difficult programming, and make your program easier to read by re-defining your problem. Say the f/2 describes a directed graph, with edges from the first argument to each of the elements in the second argument, so:

a ---> b
a ---> d
b ---> c
% etc

Then, your question is, which nodes in the graph are reachable from a given node? You can define the solution with the help of library(ugraphs).

To make all edges from an f/2:

edge(From-To) :-
    f(From, L),
    member(To, L).

You can now collect the edges, make a graph, and find which nodes are reachable from a starting node:

foo(X, L) :-
    findall(E, edge(E), Edges),
    vertices_edges_to_ugraph([], Edges, G),
    reachable(X, G, All),
    once(select(X, All, R)), % remove the node you start from
    reverse(R, L).

Per definition, a node is always reachable from itself, so you need to pick it out of the list of reachable nodes.

?- foo(a, X).
X = [g, f, e, d, c, b].

?- foo(e, X).
X = [g, f].

?- foo(g, X).
X = [].

I don't exactly understand why the order of the elements is significant. This feels a bit like a code smell.



标签: graph prolog