Prolog (Sicstus) - setof and findall combination issues

138 views Asked by At

Given a set of routes a given station has, such us :

route(TubeLine, ListOfStations).

route(green, [a,b,c,d,e,f]).
route(blue, [g,b,c,h,i,j]).
...

I am required to find names of lines that have a specific station in common. The result must be ordered, with non-repeated stations and must return an empty list, if there were no results. So, querying

| ?- lines(i, Ls).

Should give:

Ls = [blue,red,silver] ? ;
no

I tried doing the following:

lines(X, L) :- setof(L1, findall(W, (route(W, Stations),member(X, Stations)),L1), L).

However, it gives the following as an answer:

Is = [[blue,silver,red]];
no

So unordered with double braces. I tried using just findall, but the result is not ordered. I know I could then write sort function and pass that through, however I was wondering if it is possible to use just findall and setof in this instance?

1

There are 1 answers

2
CapelliC On BEST ANSWER

Actually, it's easier than your attempt, but you need to grasp the peculiar setof' behaviour wrt free variables, and account for the eventuality that an unknown station was required (setof/3 fails if there are no solutions).

 lines(X, Ls) :-
   setof(L, Stations^(route(L, Stations), member(X, Stations)), Ls)
   -> true ; Ls = [].

An easier alternative, as you said, use findall/3 exactly as you're doing (without setof!), and sort the output.