Newsgroups: comp.lang.prolog
Path: cantaloupe.srv.cs.cmu.edu!rochester!udel!gatech!howland.reston.ans.net!ix.netcom.com!netcom.com!ludemann
From: ludemann@netcom.com (Peter Ludemann)
Subject: Re: Novice prolog questions and thanks
Message-ID: <ludemannD3ssA1.2pv@netcom.com>
Organization: NETCOM On-line Communication Services (408 261-4700 guest)
References: <Pine.SOL.3.91.950209143630.11319A-100000@bingsun1>
Date: Fri, 10 Feb 1995 18:49:13 GMT
Lines: 45
Sender: ludemann@netcom8.netcom.com

In article <Pine.SOL.3.91.950209143630.11319A-100000@bingsun1>,
Lars Kellogg-Stedman  <consp01@bingsuns.cc.binghamton.edu> wrote:
>This almost works:
>
>	pathfrom(p1,p2).
>	pathfrom(p2,p3).
>	pathfrom(p3,p4).
>	pathfrom(p4,p5).
>
>	pathfrom(X,Z):-pathfrom(X,Y),pathfrom(Y,Z).
>
>However, if there are any loops in the path, this fails miserably, and 
>even this linear p1->p2->...->p5 example generates an infinite loop (try 
>pathfrom(p1,WHERE).  It sort of drops off the end...).

An easy solution to this is get XSB (where to get it is in the Prolog
FAQ) and put in a "table" directive.  No inifinite loops.

If you can't do that, then you need to pass around a list of places
visited and avoid seeing them twice.  The member/2 predicate can be
used.  You also want to differentiate between the pathfrom/2 facts and
the transitive path predicate.  Something like the following (which I
haven't tested):

	transitive_path(X,Z) :-
		path(X,[],Z).

	/* path(X,Seen,Z) finds a path from X to Z, given that
	   items in Seen have already been traversed */

	path(Z,_,Z).
	path(X,Seen,Z) :_
		pathfrom(X,Y),
		\+ member(Y,Seen),
		path(Y,[Y|Seen],Z).

	member(X,[X|_]).
	member(X,[_|Xs]) :- member(X,Xs). 

Of course, this still isn't terribly efficient, but it gets rid of
infinite loops.  (I prefer the XSB solution, which is more efficient
and easier to write.)

-- 
Peter Ludemann                      ludemann@netcom.com
