Saturday, February 19, 2011

Trailing variable in a prolog list.

Hi folks, I'm on a beginner level course in prolog, doing a map colouring problem. Here's my code.

col(Colors,Map,Coloring) :-
    checkMap(Colors,Map,Coloring).
checkMap(Colors,[Country1:Country2],Coloring) :-
    goodColor(Country1:Country2,Coloring,Colors).
checkMap(Colors,[Country1:Country2|Rest],Coloring) :-
    goodColor(Country1:Country2,Coloring,Colors),
    checkMap(Colors,Rest,Coloring).
goodColor(Country1:Country2,Coloring,Colors) :-
    mem(Country1:Color1,Coloring),!,
    mem(Country2:Color2,Coloring),!,
    mem(Color1,Colors), mem(Color2,Colors),
    not(Color1=Color2).
mem(Var,[Var|_]).
mem(Var,[_|Rest]) :-
    mem(Var,Rest).

My output looks like this:

?- col([a,b,c],[1:2,1:3,2:3],X).
X = [1:a, 2:b, 3:c|_G332] ;
X = [1:a, 2:c, 3:b|_G332] ;
X = [1:b, 2:a, 3:c|_G332] ;
X = [1:b, 2:c, 3:a|_G332] ;
X = [1:c, 2:a, 3:b|_G332] ;
X = [1:c, 2:b, 3:a|_G332] ;
fail.

Anyone know how I can get rid of the trailing variable? I know it's mostly cosmetic, but I don't see why it's there.

From stackoverflow
  • Using an incomplete data structure is a valid Prolog programming technique. If your intention is to use an incomplete data structure then one solution is:

    ground_terms([H|T1],[H|T2]) :- ground(H), !, ground_terms(T1,T2).
    ground_terms(_,[]).
    

    and change col as follows:

    col(Colors,Map,Coloring) :-
        checkMap(Colors,Map,Coloring1),
        ground_terms(Coloring1,Coloring).
    
    Pjotrovitz : What is the predicate ground/1 in there? Thanks for the answer :)
  • The trailing variable is there because mem(Var,[Var|_]) binds the unbound Coloring variable to [Var|_].

    One way to avoid it is to accumulate the map coloring e.g (very quick and extremely dirty):

    col(Colors,Map,Coloring) :-
        check(Colors,Map,[],Coloring).
    
    check(Colors,[],Coloring,Coloring).
    
    check(Colors,[Country1:Country2 | T],[],L) :-
        member(Color1,Colors),
        member(Color2,Colors),
        Color1 \== Color2,
        check(Colors,T,[Country1:Color1,Country2:Color2],L).
    
    check(Colors,[Country1:Country2 | T],Coloring,L) :-
        member(Country1:Color1,Coloring),
        member(Country2:Color2,Coloring),!,
        check(Colors,T,Coloring,L).
    
    check(Colors,[Country1:Country2 | T],Coloring,L) :-
        member(Country1:Color1,Coloring),!,
        member(Color2,Colors),
        not(member(_:Color2,Coloring)),
        check(Colors,T,[Country2:Color2|Coloring],L).
    
    check(Colors,[Country1:Country2 | T],Coloring,L) :-
        member(Country2:Color2,Coloring),!,
        member(Color1,Colors),
        not(member(_:Color1,Coloring)),
        check(Colors,T,[Country1:Color1|Coloring],L).
    

    Its a much more 'procedural' approach than yours though :-(. There's probably a more elegant way...

0 comments:

Post a Comment