Newsgroups: comp.lang.prolog
Path: cantaloupe.srv.cs.cmu.edu!rochester!udel!gatech!howland.reston.ans.net!swrinde!cs.utexas.edu!news.sprintlink.net!simtel!harbinger.cc.monash.edu.au!yarrina.connect.com.au!news.mel.aone.net.au!inferno.mpx.com.au!news.unimelb.EDU.AU!cs.mu.OZ.AU!munta.cs.mu.OZ.AU!fjh
From: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Subject: Re: Simple question(s)
Message-ID: <9527100.25405@mulga.cs.mu.OZ.AU>
Sender: news@cs.mu.OZ.AU (CS-Usenet)
Organization: Computer Science, University of Melbourne, Australia
References: <43k2d0$eom@explorer.csc.com>
Date: Wed, 27 Sep 1995 14:15:43 GMT
Lines: 81

brendan@moe.oc3s-emh1.army.mil (Brendan McKenna) writes:

>	The first one relates to the following little bit of code that removes
>duplicates from a list.  The way I am doing it, it winds up that I always remove
>all copies except the last one in the list.  What I was wondering is, is there 
>a way to do this that would keep the first occurance, and only remove the
>subsequent ones?  

Sure.  One way to do this is as follows: as you traverse the input
list, keep track of the elements you have already seen.  For each
member of the list, if you have already seen that member, then just
ignore it, otherwise insert it into the output list and into the
list of elements seen so far.

	/* untested code follows */
	no_doubles(List, NoDoublesList) :-
		no_doubles_2(List, [], NoDoublesList).

	no_doubles_2([], _, []).
	no_doubles_2([X|Xs], ElementsToRemove, NoDoublesList) :-
		( member(X, ElementsToRemove) ->
			no_doubles_2(Xs, ElementsToRemove, NoDoublesList)
		;
			NoDoublesList = [X | NoDoublesList1],
			no_doubles_2(Xs, [X | ElementsToRemove], NoDoublesList1)
		).

>	The second question I have refers to the following.  The exercise was to
>write a program to do mergesorting.  While the one I've got below gives all the
>appearances of working, it doesn't look quite right to me (particularly the
>facts where I have the "[X|[]]" lists).  In addition, this doesn't terminate --
>when I run it, I keep getting the same answer over and over again (or, more
>correctly, when I tell it to redo the goal)
[...]
>%	Exercise 3.3.1.v, mergesort(L1,L2)
>%		L2 is L1 sorted via a mergesort
>%		merge renamed to smerge to avoid collision
>%
>mergesort([],[]).
>mergesort([X|[]],[X|[]]).

The above clause is more clearly written as simply

	mergesort([X],[X]).

The notations `[X]' and `[X|[]]' both mean exactly the same thing -
a list consisting of just one element, X.

>mergesort(Xs,Ys) :-
>	split(Xs,Z1s,Z2s),
>	mergesort(Z1s,SZ1s),
>	mergesort(Z2s,SZ2s),
>	smerge(SZ1s,SZ2s,Ys).

This clause it not mutually exclusive with the above two clauses.
Try inserting an additional check `Xs = [_, _ | _]' so that the
three clauses deal with three mutually exclusive cases - lists
of zero elements, one element, or at least two elements (respectively).

>smerge([],[],[]).
>smerge([X|[]],[],[X|[]]).
>smerge([X|Xs],[Y|Ys],[X,Y|Zs]) :-
>	X @=< Y,
>	smerge(Xs,Ys,Zs).
>smerge([X|Xs],[Y|Ys],[Y,X|Zs]) :-
>	X @> Y,
>	smerge(Xs,Ys,Zs).

Hmm... isn't this missing a clause?  You need a clause to handle the
case when the first list is empty, but the second list is not.

(I can't refrain from pointing out that had this program been written
in Mercury rather than Prolog, both this error and the one above would
have been automatically detected by the Mercury compiler's determinism
checking.)

-- 
Fergus Henderson             |  "Australia is the richest country in the world,
fjh@cs.mu.oz.au              |   according to a new system of measuring wealth
http://www.cs.mu.oz.au/~fjh  |   announced by the World Bank yesterday."
PGP: finger fjh@128.250.37.3 |  - Melbourne newspaper "The Age", 18 Sept 1995.
