Path: utzoo!attcan!utgpu!jarvis.csri.toronto.edu!clyde.concordia.ca!uunet!cs.utexas.edu!tut.cis.ohio-state.edu!att!dptg!ulysses!andante!alice!pereira From: pereira@alice.UUCP (Fernando Pereira) Newsgroups: comp.lang.prolog Subject: Re: general PROLOG questions Keywords: new user.. Message-ID: <10231@alice.UUCP> Date: 9 Dec 89 06:43:33 GMT References: <5631@uhccux.uhcc.hawaii.edu> <2898@munnari.oz.au> <793@fs1.ee.ubc.ca> Reply-To: pereira@alice.UUCP () Organization: AT&T, Bell Labs Lines: 64 In article <793@fs1.ee.ubc.ca> vincel@fs0.ee.ubc.ca writes: >What about: >nth([],_,[]) :- !. >nth([Item|List],1,Item) :- !. >nth([H|T],N,Item) :- NN is N-1,nth(T,NN,Item). > >Works for any length list. We don't even have to know anything about listsize! Richard O'Keefe's temporary absence from the net is sorely felt in cases like this one. I'll try my inadequate best to replace him here (-:). Anyway, the short example above suffers from several problems: 1. Unnecessary cuts: the cut in the first clause is not needed, since its head is incompatible with those of the other to clauses, and in the intended use of the predicate the first two arguments are instantiated. 2. Unclear specification, datatype incoherence: the commonsensical definition of nth has no solutions for the empty list, so the first clause should not be there. Furthermore, using [] as some kind of 'null' value is a bad idea. [] should be used only for the empty list (I'm becoming more and more taken by strong typing...). In the example above, confusion would follow it the Item returned from one of the lower clauses were [] (it can be a list element too!) 3. The program will loop if called with N < 1 (a standard programming error not restricted to Prolog) 4. In predicates where one argument is used to select a component of another argument, it is better style (as well as more efficient in most Prolog systems) to have the selector as the first argument. Here's a cleaner version nth(1, [Elem|_], Elem). nth(I, [_|Rest], Elem) :- I > 0, J is I - 1, nth(J, Rest, Elem). If your Prolog leaves an extraneous choice point when succeeding at the base case (as unfortunately most will), a cut may be used for efficiency nth(1, [Elem|_], Elem) :- !. nth(I, [_|Rest], Elem) :- I > 0, J is I - 1, nth(J, Rest, Elem). or a conditional used instead. And now a plea: please apply simple style checks like the above to your Prolog code. It pays off in efficency, robustness and clarity. Programming (and logic programming in particular) will not be respected as an engineering discipline (as opposed to a black art) if simple principles of quality keep being ignored. Fernando Pereira AT&T Bell Laboratories Murray Hill, NJ pereira@research.att.com