[mercury-users] Circular lists

Thomas Charles CONWAY conway at cs.mu.oz.au
Thu Nov 27 13:52:24 AEDT 1997


Fergus Henderson, you write:
> > 
> > With all this talk of circular lists, I thought people might be
> > interested/amused by the following.
> > 
> > Beware, it is a complete hack, but IMHO quite cute.
> 
> Heaven forbid!  "Cute" is not the word that springs to mind ;-)
> 
> Actually you don't need to use the C interface.  You can do this
> sort of thing using the existing features of Mercury (>= 0.7.2),
> namely the `store' module, as shown below.
> 

I wrote the inflist module in 1 minute after writing the following
"chain" module this morning while waiting for hydra to reboot....

:- module chain.

:- interface.

:- import_module std_util.

:- type chain(T).

:- type handle(T).

:- pred chain__init(chain(T)::uo) is det.

:- pred chain__insert(T, chain(T), chain(T)).
:- mode chain__insert(in, di, uo) is det.

:- pred chain__insert(T, handle(T), chain(T), chain(T)).
:- mode chain__insert(in, out, di, uo) is det.

:- pred chain__first(maybe(handle(T)), chain(T), chain(T)).
:- mode chain__first(out, di, uo) is det.

:- pred chain__next(handle(T), handle(T), chain(T), chain(T)).
:- mode chain__next(in, out, di, uo) is det.

:- pred chain__prev(handle(T), handle(T), chain(T), chain(T)).
:- mode chain__prev(in, out, di, uo) is det.

:- pred chain__deref(handle(T), T, chain(T), chain(T)).
:- mode chain__deref(in, out, di, uo) is det.

:- pred chain__update(handle(T), T, chain(T), chain(T)).
:- mode chain__update(in, in, di, uo) is det.

:- implementation.

:- import_module require, store.

:- type chain(T)
	--->	chain(
			store(some_store_type),
			mutvar(elem(T), some_store_type)
		).

:- type cstore == store(some_store_type).

:- type handle(T) ==	mutvar(elem(T), some_store_type).

:- type elem(T)
	--->	empty
	;	elem(
			handle(T), % prev
			handle(T), % next
			T
		).

chain__init(mkchain(Store, First)) :-
	store__init(Store0),
	store__new_mutvar(empty, First, Store0, Store).

chain__insert(Thing, Chain0, Chain) :-
	chain__insert(Thing, _Elem, Chain0, Chain).

chain__insert(Thing, Elem, Chain0, Chain) :-
	Chain0 = chain(Store0, First0),
	store__get_mutvar(First0, FirstElem0, Store0, Store1),
	(
		FirstElem0 = empty,
		store__set_mutvar(First0, elem(First0, First0, Thing),
			Store1, Store),
		First = First0,
		Elem = First
	;
		FirstElem0 = elem(Prev, Next, Thing0),
		chain__insert2(Thing, Thing0, First0, Prev, Next,
			First, Elem, Store1, Store)
	),
	Chain = mkchain(Store, First).

:- pred chain__insert2(T, T, handle(T),  handle(T),  handle(T), 
		handle(T),  handle(T), cstore, cstore).
:- mode chain__insert2(in, in, in, in, in, out, out, di, uo) is det.

chain__insert2(NewThing, Thing, This, Prev, Next, First, New,
		Store0, Store) :-
	compare(Res, NewThing, Thing),
	( Res = (<) ->
		store__new_mutvar(elem(Prev, This, NewThing), New,
			Store0, Store1),
		First = New,
		store__set_mutvar(This, elem(New, Next, Thing),
			Store1, Store2),
		store__get_mutvar(Prev, PrevElem, Store2, Store3),
		(
			PrevElem = empty,
			error("chain__insert: prev internal error")
		;
			PrevElem = elem(PPrev, _, PrevThing),
			store__set_mutvar(Prev, elem(PPrev, New, PrevThing),
				Store3, Store)
		)
	;
		First = This,
		chain__insert3(NewThing, This, Next, New, Store0, Store)
	).

:- pred chain__insert3(T, handle(T), handle(T), handle(T), cstore, cstore).
:- mode chain__insert3(in, in, in, out, di, uo) is det.

chain__insert3(NewThing, First, This, New, Store0, Store) :-
	( This = First ->
		store__get_mutvar(This, ThisElem, Store0, Store1),
		(
			ThisElem = empty,
			error("chain__insert: internal error")
		;
			ThisElem = elem(Prev, Next, ThisThing),
			store__new_mutvar(elem(Prev, This, NewThing), New,
				Store1, Store2),
			store__set_mutvar(This, elem(New, Next, ThisThing),
				Store2, Store3),
			store__get_mutvar(Prev, PrevElem, Store3, Store4),
			(
				PrevElem = empty,
				error("chain__insert: another prev internal")
			;
				PrevElem = elem(PPrev, _, PrevThing),
				store__set_mutvar(Prev,
					elem(PPrev, New, PrevThing),
					Store4, Store)
			)
		)
	;
		store__get_mutvar(This, ThisElem, Store0, Store1),
		(
			ThisElem = empty,
			error("chain__insert: another internal error")
		;
			ThisElem = elem(Prev, Next, ThisThing),
			compare(Res, NewThing, ThisThing),
			( Res = (<) ->
				store__new_mutvar(elem(Prev, This, NewThing),
					New, Store1, Store2),
				store__set_mutvar(This,
					elem(New, Next, ThisThing),
					Store2, Store3),
				store__get_mutvar(Prev, PrevElem,
					Store3, Store4),
				(
					PrevElem = empty,
					error("chain__insert: ya prev internal")
				;
					PrevElem = elem(PPrev, _, PrevThing),
					store__set_mutvar(Prev,
						elem(PPrev, New, PrevThing),
						Store4, Store)
				)
			;
				chain__insert3(NewThing, First, Next, New,
					Store1, Store)
			)
		)
	).

chain__first(MFirst, chain(Store0, First), mkchain(Store, First)) :-
	store__get_mutvar(First, FirstElem, Store0, Store),
	(
		FirstElem = empty,
		MFirst = no
	;
		FirstElem = elem(_, _, _),
		MFirst = yes(First)
	).

chain__next(This, Next, chain(Store0, First), chain(Store, First)) :-
	store__get_mutvar(This, ThisElem, Store0, Store),
	(
		ThisElem = empty,
		error("chain__next: no elements!")
	;
		ThisElem = elem(_, Next, _)
	).

chain__prev(This, Prev, chain(Store0, First), chain(Store, First)) :-
	store__get_mutvar(This, ThisElem, Store0, Store),
	(
		ThisElem = empty,
		error("chain__prev: no elements!")
	;
		ThisElem = elem(Prev, _, _)
	).

chain__deref(This, Elem, chain(Store0, First), chain(Store, First)) :-
	store__get_mutvar(This, ThisElem, Store0, Store),
	(
		ThisElem = empty,
		error("chain__deref: empty!")
	;
		ThisElem = elem(_, _, Elem)
	).

chain__update(This, NewThing, chain(Store0, First), chain(Store, First)) :-
	store__get_mutvar(This, ThisElem, Store0, Store1),
	(
		ThisElem = empty,
		error("chain__deref: empty!")
	;
		ThisElem = elem(Prev, Next, _),
		Elem = elem(Prev, Next, NewThing)
	),
	store__set_mutvar(This, Elem, Store1, Store).

:- func mkchain(cstore, handle(T)) = chain(T).
:- mode mkchain(in, in) = uo is det.

mkchain(Store0, First0) = chain(Store, First) :-
	unsafe_promise_unique(Store0, Store),
	unsafe_promise_unique(First0, First).
-- 
ZZ:wq!
^X^C
Thomas Conway               				      conway at cs.mu.oz.au
AD DEUM ET VINUM	  			      Every sword has two edges.



More information about the users mailing list