stack, queue, counter, bag, gensym
All data structures come with a uniform user interface. They are
implemented efficiently on the basis of the Oz base environment. All
data structures are given in two styles: the Oz-library style and the
object-as-record style. The package also contains some further data
structures. They previously were only available in the Oz-library
style:
dictionary, array, cell
put, get
These functions are not only available with the uniform names, but
also with their standard names. The put
function of a
cell for instance is usally called assign
and its
get
function access
. And of course, you can
push
or pop
elements onto or from a stack,
as you might expect.
Other uniform function names that are only available if they make
sense are:
condGet, member, isEmpty, size, clone, toList,
toRecord, toRecordLabel
The Oz library style is the same style as used in the Oz base
environment. The idea is that the functions of all instances of data
structures are provided by a comon module. For example, the
functionalities for all dictionaries are collected in the module
We first show how to use a stack in object as record style. Here, the
stack
The documenting style is adopted from the Oz Base
Environment Documentation. It is described in the sections
"Variable Status" and "Description Format" in chapter Type
Structure and Description Format.
There are two constructors for stacks:
Dictionaries in the object-record style are derived
straightforwardly from those in the Oz base environment.
But there are two important differences that we would
like to point out.
First there is a quite useful procedure
There are two constructors for dictionaries:
Arrays in are, very much like dictionaries, derived
straightforwardly from the arrays in the Oz base environment. Like
the dictionaries the arrays provide a An array is a record with the following type:
The gensym.ozf functor provides generators for successively
different atoms. Such a generator is a function in
An important fact about the Gensym functions is that you can even
use them in search and in different computation spaces, where they
still return the expected values, unlike With Example:
In case that you did not already install By default, all files of the package are installed in the user's
~/.oz directory tree. In particular, all modules are
installed in the user's private cache.
This package provides implementations of data structure in the
object-as-record style at the URI x-ozlib://niehren/base. The corresponding
versions in the Oz-library style are available at the URI x-ozlib://niehren/base/lib.
Example
S
is a record of functions push
,
pop
, etc:
Here is how to use a stack in the Oz-library style. Now a stack
declare [Stack] = {Module.link ['x-ozlib://niehren/base/stack.ozf']}
declare S = {Stack.new}
{S.push 1} %% push 1 onto the stack
{S.push 2} %% push 2 onto the stack
{Inspect {S.pop}} %% remove and inspect the top most element
{Inspect {S.toList}} %% inspect the stack's content
S
is the first argument expected by the functions of the
module stack
:
declare [Stack] = {Module.link ['x-ozlib://niehren/base/lib/stack.ozf']}
declare S = {Stack.new}
{Stack.push S 1} %% push 1 onto the stack
{Stack.push S 2} %% push 2 onto the stack
{Inspect {Stack.pop S} %% remove and return the top most element
{Inspect {Stack.toList S}} %% inspect the stack's content
Manual
In the following we will describe all data structures in detail. We
will use the object-as-record style variants for explanation because
function types are smaller and therefore more concise. However, with
the above information the following is easy applicable to the
Oz-library style variants.
Stack
creates a new and empty stack and
Stack.new : -> stack
creates a new stack initialized with the given list, so that the head
of the list becomes the topmost element. A stack has the following
type:
Stack.newFromList : list(value) -> stack
The type can also be specified by modes as usual
in the Oz documentation:
type stack = unit(push : value ->
pop : -> value
isEmpty : -> bool
toList : -> list(value)
top : -> value
clear : ->
clone : -> stack
member : value -> bool
size : -> int
put : value ->
get : -> value)
pushes {S.push X}
X
onto the stack S
.
pops the topmost element from {S.pop ?X}
S
and returns it in
X
. Raises empty
iff S
is
empty.
tests whether {S.isEmpty ?B}
S
is empty and returns the boolean result
in B
.
returns the list containing the elements of {S.toList ?Xs}
S
in
Xs
. The list returned is the list that is used to
implement the stack, so this operation needs constant time. The
elements in Xs
are in the same order they would appear by
subsequent calls to get
.
returns the topmost element from {S.top ?X}
S
into X
without changing S
's state. Raises empty
iff S
is empty.
erases {S.clear}
S
to an empty stack.
returns an independent clone of {S.clone ?R}
S
in R
.
tests whether {S.member +X ?B}
S
contains X
using
==
and returns the boolean result in B
.
returns the size of {S.size ?I}
S
in I
.
is a synonym for {S.put X}
{S.push X}
.
is a synonym for {S.get ?X}
{S.pop ?X}
.
Queue
There are two constructors for queues:
creates a new and empty queue and
Queue.new : -> queue
creates a new queue initialized with the given list, so that the
elements in the list are in the same order they would appear by
subsequent calls to Queue.newFromList : list(value) -> queue
deq
. A queue has the following type:
The type can also be specified by modes as usual in the Oz
documentation:
type queue = unit(deq : -> value
enq : value ->
isEmpty : -> bool
toList : -> list(value)
top : -> value
clear : ->
clone : -> queue
member : value -> bool
size : -> int
put : value ->
get : -> value)
enqueues {Q.enq X}
X
into Q
.
dequeues the next element from {Q.deq ?X}
Q
and returns it in
X
. Raises empty
iff Q
is
empty.
tests whether {Q.isEmpty ?B}
Q
is empty and returns the boolean result
in B
.
returns the list containing the elements of {Q.toList ?Xs}
Q
in
?Xs
. This operation needs linear time. The elements in
?Xs
are in the same order they would appear by subsequent
calls to deq
.
returns the topmost element from {Q.top ?X}
Q
into X
without changing Q
's state. Raises empty
iff Q
is empty.
erases {Q.clear}
Q
to an empty queue.
returns an independent clone of {Q.clone ?R}
Q
in R
.
tests whether {Q.member +X ?B}
Q
contains X
using
==
and returns the boolean result in B
.
returns the size of {Q.size ?I}
Q
in I
.
is a synonym for {Q.put X}
{Q.push X}
.
is a synonym for {Q.get ?X}
{Q.pop X}
.
Counter
A counter holds one integer that can be incremented or set to an
arbitrary integer. There are two constructors for counters:
creates a new counter initialized with 0 and
Counter.new : -> counter
creates a new counter initialized with the given integer. A counter
has the following type:
Counter.newFromInt : int -> counter
The type can also be specified by modes as usual in the Oz
documentation:
type counter = unit(inc : ->
set : int ->
show : -> int
next : -> int
clone : -> counter
put : int ->
incr : ->
init : int ->
get : -> int
toInt : -> int
increments {C.inc}
C
by 1.
sets the current value of {C.set +I}
C
to I
.
returns the current value of {C.show ?I}
C
in I
.
increments {C.next ?I}
C
by 1 and returns the resulting integer in
I
.
returns an independent clone of {C.clone ?R}
C
in R
.
is a synonym for {C.incr +I}
{C.inc +I}
.
is a synonym for {C.put +I}
{C.set +I}
.
is a synonym for {C.init +I}
{C.set +I}
.
is a synonym for {C.get ?I}
{C.show ?I}
.
is a synonym for {C.toInt ?I}
{C.show ?I}
.
Dictionary
collect: feature x value ->
which adds a value for some key to a collecting list. The
actual list can be access as the entry of the key.
Second, the type of toRecord:->record
differs from what one might expect. This function converts
the dicitionary to a record whose label is the unit
.
If you want to specify another label then you can still use
toRecordLabel:literal->record
that does exactly
what the toRecord
function of the Oz base
environment does.
creates a new and empty dictionary and
Dictionary.new : -> dictionary
creates a new dictionary initialized with the feature/value pairs of
the given record. A dictionary is a record with the following type:
Dictionary.newFromRecord : record -> dictionary
The type can also be specified by modes as usual
in the Oz documentation:
type feature = literal | integer
type dictionary = unit(put : feature x value -> dict
get : feature -> value
hasFeature : feature -> bool
condGet : feature x value -> value
remove : feature ->
removeAll : ->
keys : -> list(feature)
entries : -> list(feature#value)
items : -> list(value)
toRecord : -> record
toRecordLabel : literal -> record
isEmpty : -> bool
size : -> int
collect : feature x value -> dict
clone : -> dict
dict : -> stdlib-dict
clear : ->
condSelect : feature x value -> value
member : feature -> bool
toKeys : -> list(feature))
sets the item of {D.put +LI X}
D
under the key LI
to
X
.
returns the item of {D.get +LI ?X}
D
under the key LI
in
X
. Raises an exception if LI
is not a valid
key of D
.
tests whether {D.hasFeature +LI ?B}
D
has an entry with the feature
LI
and returns the boolean result in B
.
returns the item of {D.condGet +LI Default ?Y}
D
under the key LI
as
Y
iff LI
is a valid key of D
.
Otherwise, returns Default
.
removes the entry with the key {D.remove +LI}
LI
from D
iff
LI
is a valid key of D
. Otherwise, does
nothing.
resets {D.removeAll}
D
to an empty dictionary.
returns a list of all valid features for {D.keys ?LIs}
D
in
LIs
.
returns a list of all entries in {D.entries ?Ts}
Ts
where each entry has
the form Feature#Item
.
returns a list of all items in {D.items ?Xs}
Xs
.
returns a record containing all feature/item pairs of {D.toRecord ?R}
D
as its fields in R
. This record R
will get
the label unit
. Note that
ToRecord
differs to the corresponding function in the
Oz base environment. But you can still use toRecordLabel
if you want to custom your own label.
works like {D.toRecordLabel +LI ?R}
toRecord
except that it gives the possibility
to specify a custom label (LI
). Note that this
function does exactly what the function ToRecord
in the
Oz base environment does despite of its different name.
tests whether {D.isEmpty ?B}
D
is empty and returns the boolean result
in B
.
returns the element count of {D.size ?I}
D
in I
.
collects {D.collect +LI X}
X
in the list under the feature LI
in D
. More precise, it will set D
's item
under LI
to X|{D.condGet LI nil}
.
Note that collectors are not available for the dictionaries of
the base environment.
returns an independent clone of {D.clone +R}
D
in R
.
returns the Oz base environment dictionary through which
{D.dict}
D
is implemented.
is a synonym for {D.clear}
{D.removeAll}
.
is a synonym for {D.condSelect +LI X ?Y}
{D.condGet +LI X ?Y}
.
is a synonym for {D.member +LI ?B}
{D.hasFeature +LI ?B}
.
is a synonym for {D.toKeys ?LIs}
{D.keys ?LIs}
.
Bag
A bag is a simple data structure that gives the possibility to put
values into the bag, to test whether a given value is in the bag and
to return the elements in a bag as a list. A bag is essentially the
same as a stack. The only difference is that it does not provide
functions for getting single elements from it (with pop
or top
). There are two constructors for bags:
creates a new and empty bag and
Bag.new : -> bag
creates a new bag initialized with the elements of the given list. A
bag has the following type:
Bag.newFromList : list(value) -> bag
The type can also be specified by modes as usual in the Oz
documentation:
type queue = unit(put : -> value
member : value -> bool
isEmpty : -> bool
toList : -> list(value)
clear : ->
clone : -> queue
size : -> int)
puts {B.put X}
X
into B
.
tests whether {B.member +X ?B1}
B
contains X
using
==
. Returns the boolean result in B1
.
tests whether {B.isEmpty ?B1}
B
is empty and returns the boolean result
in B1
.
returns the list containing the elements of {B.toList ?Xs}
B
in
Xs
. The list returned is the list that is used to
implement the stack, so this operation needs constant time.
resets {B.clear}
B
to an empty queue.
returns an independent clone of {B.clone ?R}
B
in R
.
returns the size of {B.size ?I}
B
in I
.
Array
collect: int x value
->
procedure that lets you collect values in a list at a given
index in the array.
creates a new and empty array {Array.new +Low +High +InitVal ?A}
A
. Low
and
High
(both integers) are the bounds for the indices of
the resulting array. So {A.put I X}
and X={A.get
I}
are legal iff Low<=I<=High
. All items of the
array are initialized to InitVal
.
type array = unit(low : int
high : int
put : int x value ->
get : int -> value
collect : int x value ->
inc : int ->
clone : -> array
toRecord : -> record
toRecordLabel : literal -> record)
low
and high
are the index bounds.
sets the item of {A.put +I X}
A
under the index I
to
X
.
returns the item of {A.get +I ?X}
A
under the index I
in
X
. Raises an exception if I
is not a valid
index of A
, i.e. if I
is not in
A.low...A.high
.
has the same semantics as {A.collect +I X}
{A.put I X|{A.get I}}
.
has the same semantics as {A.inc +I X}
{A.put I 1+{A.get I}}
. As a
precondition {A.get I}
must be an integer. Otherwise an
exception will be raised.
returns a copy of {A.clone ?R}
A
in R
, such that
{A.get I}
is token equal to {R.get I}
for
I
in A.low...A.high
.
returns a record {A.toRecord ?R}
R
with label unit
and
features A.low...A.high
such that {A.get I}
is token equal to R.I
for I
in
A.low...A.high
.
is like {A.toRecordLabel +LI ?R}
toRecord
except that you can specify an custom
label LI
.
Gensym
A generator takes a virtual string virtual-string -> atom
.
V
and returns a
concatenation of V
and an integer I
.
Successive calls increment I
. Counting starts from
1
.
{NewName}
which
can return equal names in different spaces.
G={New}
you create a new symbol generator
G
. Additionally the Gensym functor provides a default
symbol generator Gensym
.
This shows:
declare [Gensym] = {Link ['x-ozlib://base/gensym.ozf']} in
{Show {Gensym.gensym 'stem'}}
{Show {Gensym.gensym 'stem'}}
{Show {Gensym.gensym 'stem'}}
local
G = {Gensym.new}
in
{Show {G 'kuckuck'}}
end
{Show {Gensym.gensym 'stem'}}
stem1
stem2
stem3
kuckuck1
stem4
Cell
Cells are directly implemented through the cells of the Oz base
environment. But this package's cells have a slightly different
exchange
function that takes the old value instead of the
new one as its last argument. Apart from that the uniform names
put
and get
are given. There is one
constructor
that expects a value Cell.new : value -> cell
X
and creates a new cell with
X
as its initial element. A cell is a record with the
following type:
The type can also be specified by modes as usual
in the Oz documentation:
type cell = unit(put : value ->
get : -> value
exchange : value -> value
clone : -> cell
access : -> value
assign : value ->
set : value ->)
sets the content of {C.put X}
C
to X
.
returns the current content of {C.get ?X}
C
in X
.
sets the cells content to {C.exchange New ?Old}
New
and returns the old content
in Old
. Note that the order of the arguments
New
and Old
are reverse in comparison to the
Oz base environment's Exchange
function. This way you
can use exchange
like a usual function that takes the new
value and evaluates to the old one.
returns a clone of {C.clone ?R}
C
in R
.
is a synonym for {C.assign X}
{C.put X}
.
is a synonym for {C.set X}
{C.put X}
.
is a synonym for {C.access ?X}
{C.get ?X}
.
Installation
Download the file base-xx.pkg
, where xx should be
replaced by the current version number, and execute
ozmake --freshen --package=base-xx.pkg
ozmake
on
your machine, note that it is also available in the Mogul archive.
Joachim Niehren