debray@arizona.edu (Saumya Debray) (04/10/88)
In article <522@ecrcvax.UUCP>, micha@ecrcvax.UUCP (Micha Meier) writes: > There is no reasonable argument to force people to use > tail-recursive loops instead of repeat-fail loops; > if I'm using temporary structures and I know that with the > recursive loops they are going to be garbage collected whereas > with repeat-fail loops they are just popped, I will always > prefer the latter and the standard should support me > by providing a built-in repeat/0, since its full functionality > cannot be provided by other means. There may or may not be arguments to *force* anyone to avoid failure- driven loops, but there are a couple of reasons one might want to avoid them anyway: (1) writing failure-driven loops that behave "correctly" is trickier than one might think at first. E.g., consider the following loop to process each element of a list: p([]). p([X|L]) :- process(X), p(L). The "obvious" failure-driven version of this is p(L) :- member(X,L), process(X), fail. p(_). In fact, the two loops are NOT equivalent, even if we assume that the predicate "process" is deterministic. [Hint: consider what happens if "process" fails for some element of the list.] (2) It's not too hard to automate the transformation from tail-recursive loops to failure-driven loops (with a little guidance from the user, in the form of simple compiler directives), especially for the usual case of deterministic loops. (I won't even mention things like "declarative readings", since Real Programmers don't care much about that kind of wimpy stuff anyway :-) -- Saumya Debray CS Department, University of Arizona, Tucson internet: debray@arizona.edu uucp: {allegra, cmcl2, ihnp4} !arizona!debray