Copyright © 1994, 1995, 1996 The OPAL Group
A library is one of the integral components of modern languages. Its
function is to relieve the user of the task of constantly redefining
standard structures. This is especially true for OPAL, since only two
structures, BOOL
and DENOTATION
are predefined. A library for
OPAL, containing most data types and functions needed for everyday use,
has been developed in recent years.
These structures do belong to the OPAL release, but they are not part of the language. Most of them are written in OPAL and only some are substituted by handwritten code (see Handcoded Structures) for reasons of efficiency (both space and time). This difference is not apparent to the OPAL user.
This paper offers you an overview of BIBLIOTHECA OPALICA, so that you will be able to use (and abuse) the structures in the library. That is, you will not find explanations of the functions, but you will learn where these explanations are located. If you need information about a particular function, please have a look at the signature parts.
It is not the purpose of this paper to give you an introduction to OPAL; for this you are referred to The Programming Language OPAL -- The Implementation Language and The OPAL Tutorial. Neither does the paper serve as an introduction to the compilation system, which is explained in A User's Guide to the OPAL Compilation System.
We first outline the structuring principles which were used in the design of the library. Then, we proceed through the library structures explaining what types are defined and what additional structures are available. Last, we turn to some particularities of BIBLIOTHECA OPALICA. The appendix contains, among other topics, a list of the currently known bugs and an aid to converting programs from the old library to BIBLIOTHECA OPALICA.
The OPAL library has matured in recent years and summarizes the experience of several years of functional programming. We would like to also include your experience in BIBLIOTHECA OPALICA. So, if you have any suggestions or contributions to make, please do not hesitate to drop us a line or send us a piece of code which may appear in the next release of BIBLIOTHECA OPALICA.
The OPAL Group is reachable via email: opal@.cs.tu-berlin.de
.
The OPAL distribution is available via WWW
at the URL http://uebb.cs.tu-berlin.de/~opal/
BIBLIOTHECA OPALICA consists of more than 100 different structures. Lest the user get lost, this multitude of structures clearly requires a structure of its own.
The first principle of structuring is of course the division of structures according to their kind, i.e. predefined structures, parameterized structures, environment access structures and the like. This is detailed in Survey of Structures.
There are, however, other structuring principles which are valid across these divisions. One of them is the naming of structures which follows certain principles and allows you to conclude some information about a structure from its name.
The other is the principle that similar functions have the same name in OPAL, even if they work on different data types. Typical examples of such functions are functions for converting data types to textual representation.
Roses smell as sweet by any other name, and likewise the semantics of a structure is not affected by its name. To the user, however, the name of a structure provides valuable clues about the content. By adhering to naming principles, the task of remembering the existing structures is also made easier.
In BIBLIOTHECA OPALICA the following principles are used:
nat
), while structure names are
capitalized (e.g. Nat
).
CharConv
, SetConv
) contain functions
that convert from data type type into another type, while preserving
information; i.e. they are (in principle) invertible. Typical examples are
conversions to text or converting different types of numbers.
This also works the other way round: If you are looking for a function which
converts members of type type, it is usually found in Structure
TypeConv. There are, however, exceptions to this rule:
There is no Structure DenotationConv
. Conversions from
denotation
to type are considered to be a kind of
"pseudo-constructor" and are therefore placed in Structure Type.
Conversions from sequences to another aggregate type
(see AggregateTypes) are likewise not included in SeqConv
but in
TypeConv.
SetFilter
) take a
bool-valued function and an aggregate type and remove those elements which
--- as required -- either fulfill or do not fulfill the given predicate.
SeqFold
, SeqReduce
, and so on) contain
functions which connect every element of an aggregate type with a given
function. Reducing requires a start value while folding does not, but the
latter is more restrictive, e.g. it is not defined on empty objects.
SeqMap
, SetMap
, and their counterparts for
other aggregate types, we find functions for applying one or several
functions to every element of the aggregate type.
SetByPred
) or
different methods for defining certain functions (e.g. orderings:
OrderingByInjection
).
Other kinds of structures are still in the development stage and will be added in later releases.
Orthogonality means that functions which perform similar tasks are named similarly. The principles of structuring structures obviously support sticking to the "Principle of Least Astonishment".
Also note that differently implemented types have the same name, and can
therefore easily be replaced by another implementation: simply change the
imported structure and recompile the code. So for sets of natural numbers
you can choose whether to use the ordinary implementation or the
bitstring-oriented implementation by switching from IMPORT Set[nat]
ONLY set {} + in ...
to IMPORT Bitset ONLY set {} + in
...
.
The reader should particularly note the following:
` :
type-> denotation
. If the
type is parameterized, the functionality is augmented by functions for
converting the parameter type, e.g. sequences:
` : (data -> denotation) -> seq -> denotation
.
The only exception is the type
denotation
itself. Even for types like
set'SetByPred
(see AggregateTypes) which do
not provide a sensible textual representation,
a function which returns a fixed text
describing the type is supplied.
The function `
is located in Structure TypeConv.
denotation
to type is given, this function
is called !
and located in Structure Type.
as
Type, e.g. asNat
for a function which converts type
int
to type nat
. The exceptions are the functions `
and
!
(see above).
!
#
%
.. iter
*
/ (\)
|
exist? forall?
We will now take a look at the structures in BIBLIOTHECA OPALICA. We will not examine each and every structure, rather will provide explanations concerning each group of structures. There will be no further comment on structures whose purpose is explained by the naming principles (see What's in a Name? -- Naming of Structures).
The structures of BIBLIOTHECA OPALICA have been grouped into five subsystems, some of which have been further divided into subsubsystems. The user need not be aware of the structure of BIBLIOTHECA OPALICA for using OPAL and the OPAL Compilation System. Searching for information about the library is made easier, though, if you know about the structure.
Internal
Internal
contains structures which are dependent on the
actual implementation.
BasicTypes
Functions
AggregateTypes
System
System
provide access to the
environment. This encompasses structures for debugging, access to the
facilities of the operating system and, last but not least, structures for
input and output.
The subsystem Internal
is divided into further subsystems. The user sees only the subsubsystem Strange
.
As the name suggests, these structures are not for everyday use. They do have their purpose, but think twice before you use them. They are not semantically safe and, in most cases, you will be able to do very well without them.
CAST
cast[a,b](cast[b,a](x))
yields x
again, and be
assured that casting, say pair[nat, char]
to
seq[option[string]]
, will cause considerable confusion.
EQUALITY
INLINE
Basic Types are finitely or infinitely enumerable types. Currently, the following types are members of this subsystem:
bool
bool
is a built-in sort. The predefined functions
can be looked up in structure BOOL
. Another structure allows for
converting bool
to denotation
.
char
PrintableChar
which contains definitions for the ASCII character set.
denotation
denotation
is predefined. The predefined signature is called
DENOTATION
. The structure Denotation
supplies additional
functions which make usage of denotations possible.
nat, int, real
64
are not special to OPAL ---
they are like any other identifier. Hence you have to define other
numbers for yourself. The advice is to define a constant with an appropriate
name, e.g. `DEF hashtablesize == "497"!'.
The functions !
are very strict and do not accept anything besides
the indicated characters ("anything" includes whitespace!). This is to
prevent you from typing mistakes(1).
rel, subrel
void
nil
.
ABORT
The Functions
subsystem is divided into three parts: General
for composition, iteration and the like, Orderings
for constructing
ordering relations, and Special
for structures which need special
care in their usage.
funct
Compose, ComposePar
Control
Predicate
When defining an (enumerated) type, defining the ordering relations by yourself can often be both tedious and lead to errors. The structures in this subsystem facilitate the task:
OrderingByInjection
OrderingByLess
InducedRel
Functions provided by structures of this subsystem generally come with the warnings "handle with care" and "use only, if you know what you are doing".
AcceleratorC, AcceleratorF
The concept of aggregating elements to a single entity is one of the most important in functional programming. BIBLIOTHECA OPALICA offers you many different ways to do this:
This subsystem contains structures for the use of Cartesian products of types. Our experience is that more than four sorts are usually not needed.
Type void
may be considered as the empty product (see BasicTypes).
pair, triple, quad
pair
can be compared. Note, that type quad
is defined in the
Structure Quadruple
.
AnonPair, AnonTriple, AnonQuadruple
**
. Hence, only the selectors are defined.
This subsystem contains structures for disjoint union of data types.
Type void
may be considered as the empty union (see BasicTypes).
option
void
(see BasicTypes) with an arbitrary other data type.
This type is useful for fusing two functions like test? : some ->
bool
and select: some -> data
(where select
is undefined
when test?
fails) into a single function testAndSelect: some ->
option[data]
.
union
Here you will find structures for dealing with aggregate types where number and ordering of elements matters.
seq
SeqIndex
), special variants of mapping (SeqMapEnv
),
structures for dealing with nested sequences (SeqOfSeq
), for sorting
sequences (SeqSort
) and for combining sequences of equal length
(SeqZip
).
string
string
can essentially be treated as an instantiation of
type seq
with type char
. Some additional functions, which
ensure backwards compatibility with the old library, are also available.
There is no structure for nested strings or for combining two strings of the
same length; the comparison operators are defined in the base structure.
For a discussion about the difference to type denotation
, see
String vs. Denotation.
union
BTUnion
and is a disjoint union of
basic types, i.e. bool, nat, int, real, char, string
and
denotation
. It is used in the structures for formatted input and
output.
StringFormat, StringScan
union'BTUnion
. The usage is
similar to that of the functions printf
and scanf
from
C
, so that usage of the functions from BIBLIOTHECA OPALICA
should be no more difficult than use of the functions from stdio
of
ANSI-C.
Tree-like aggregates store the data in binary trees. We have general binary trees (in the following often simply called trees), heaps and balanced search trees.
tree
~'TreeCompare
compares trees of differenty types. The other
members of this family are standard (see What's in a Name? -- Naming of Structures). Note that
there are more variants of mapping and reducing functions than e.g. on
sequences.
IndexingOfTrees
heap
bstree'BSTree
1/w <= size(left) / size(right) <= w
, where w
is a small positive natural number.)
Set-like aggregates are similar to sequences, but order of elements does not matter, and in most cases it also does not matter how often an element is added to an aggregate.
There are five different implementations of sets. This plentifulness shows that there is no ideal implementation for every purpose. The advantages and disadvantages of the additional implementations are given below.
set'Set
SetConstr
comprises functions for Cartesian product and
disjoint union of sets, the other structures adhere to the naming principles
(see What's in a Name? -- Naming of Structures). All structures take as an additional
parameter an ordering predicate, otherwise functions like subset
or
in
cannot be implemented(2).
set'SetByInj
set'SetByPred
set'SetByBST
set'Bitset
SetOfNat
. This type is handcoded and provides an
efficient (with respect to time and space) device for dealing with sets of
small natural numbers.
bag
set'Set
).
Here you can find structures which implement finite mappings.
map
MapInvert
) and for composing two maps (MapCompose
).
array
This subsystem subsumes all structures which provide functions for
communicating in some manner with the environment. It is in turn divided
into four subsystems: Debugging
contains structures for support in
debugging OPAL programs (surprise, surprise!), Commands
provides
the basic declarations for the OPAL Command Script I/O, the structures
in Streams
define a simple interface for accessing files, and
Unix
contains structures tailored for OPAL programs which run
under Unix
.
This subsystem contains just one structure, which in our opinion could not be assigned to any of the other subsystems.
DEBUG
This subsystem comprises structures which define functions on commands which are the base type for the OPAL Command Script I/O, and some structures for communicating with the environment which are independent from the underlying operating system.
com
com
is essential for I/O in OPAL. It is
always parameterized with the type which is to be passed to the next
command. If there is no such type, you have to use type void
(see BasicTypes). ComAction
defines abbreviations for the
instance com[void]
. Means for composing commands are given in
ComCompose
and ComCheck
; ComSeqReduce
reduces a
sequence to a single command. ComChoice
finally provides external
choice between two commands.
agent'ComAgent[result]
ComService
). A special command for delaying an agent is provided
in the structure ComTimeout
.
sap'ComService[in, out]
Env
Random
Streams are a simple and abstract means for reading or writing data from or to a file.
Stream
BinStream
The structures described here are tailored especially for the Unix operating system. If OPAL is ever run under another operating system, these structures will most likely be missing.
For the current release, several structures have been added, which provide
Posix conformant access to system calls. See below under ProcessCtrl
,
Signal
, UserAndGroup
and Wait
.
file
File
and BinFile
correspond roughly to
Stream
and BinStream
(see Streams). They provide functions
for input and output to and from files but are more flexible than the
structures in the subsystem Stream
.
FileSystem
FileSystemFun
contains some convenient functions for dealing with
file modes.
ProcessCtrl
Process
which is no longer
supported but still contained. It provides functions for creating,
terminating, mutate processes, getting information about one's own process,
and changing some of the attributes of a Unix process (group ids, working
directory and the like).
Signal
time
UserAndGroup
UnixFailures
Wait
Some structures in BIBLIOTHECA OPALICA are not implemented in OPAL, rather are handcoded and implemented in the target language of the OPAL compiler. This is done for two different reasons.
One reason is that access to the environment must be provided by some kind of runtime system. This runtime system is not one monolithic block of code with which every OPAL program is burdened. Instead, each structure which accesses different parts of the environment adds only the necessary code.
The other reason is that some basic data types are already supported by the target language. So, for reasons of efficiency, some data types have been handcoded. In contrast to the structures which provide access to the environment, these structures could have been implemented in OPAL.
If, for either of these reasons, you wish to add some handcoded structures to your system, you are kindly referred to the Handcoder's Guide which is included in the OPAL distribution.
Numbers belong to the family of handcoded structures
(see Handcoded Structures). You should never make assumptions about possible sizes
of numbers, since these may change in later releases of BIBLIOTHECA
OPALICA. Use the constants min
and max
wherever possible.
The following (in)equalities are guaranteed to hold in every implementation of OPAL:
min'Nat = 0
max'Nat >= 1073741822
min'Int <= -536870911
max'Int >= 536870910
min'Real <= -1e+37
max'Real >= 1e+37
The current implementation exceeds these bounds.
In BIBLIOTHECA OPALICA two types designed for textual representation
are available namely denotation
and
string
. Both are implemented differently.
The type denotation
should be used for text which does not change
very often, since insertions and deletions are relatively expensive. Space
requirements, on the other hand, are low. This type is best used for
messages and constant strings.
The type string
has a user interface which is almost identical to
that of sequences. In particular, all higher-order functions are available
for strings, so operations on texts can now directly be defined on type
string
. Note that strings are implemented differently than
sequences, so operations on strings are faster than operations on sequences
of character, and space consumption is lower.
ABORT
is a special function. It is essentially a function which
yields the undefined value of the parameter type. Hence, you can use this
function to replace the automatically inserted error messages with your own
messages, which may provide more information about the real cause.
The most interesting feature about ABORT
is that tests for
ABORT
are eliminated completely if the optimization switch -op
is set. Thus, you can develop your program with informative error messages,
then turn on the compiler switch and eliminate all the (expensive) checks
for definedness.
BIBLIOTHECA OPALICA is only the latest development of the OPAL library.
The predecessor of BIBLIOTHECA OPALICA was designed by Wolfram
Schulte, together with Andreas Fett and Gottfried Egger; the
structures which are now found in subsystem Commands
were designed by
Gottfried Egger and Wolfram Schulte.
The restructuring of the library is the result of fruitful discussions with Wolfgang Grieskamp, Joachim Faulhaber, Mario S@"udholt and Sabine Dick.
The library has profited from many suggestions from (in alphabetical order) Olaf Brandes, Christoph Breitkopf, Gottfried Egger, Sebastian Erdmann, Andreas Fett, Christian Maeder and Burkhart Wolff.
The text was carefully proofread by Niamh Warde.
There are currently no known bugs or flaws in BIBLIOTHECA OPALICA.
When a new library for OPAL was announced, some people feared they would have to forget all they knew about the old version, and learn the whole new library from scratch. This is not the case.
The most important change is the finer structuring. The old library was divided into three subsystems, two of which were of no interest for ordinary users. Now, BIBLIOTHECA OPALICA is divided into many sub- and subsubsystems. The structuring has no significance for the user as far as the OPAL Compilation System is concerned.
The other important change is the treatment of text, which involves the
types denotation
and string
. This is detailed in String vs. Denotation.
BIBLIOTHECA OPALICA is highly, but not fully compatible with the former library. Code which was written using the old library has to be adapted. We distinguish two kinds of adaptations:
IMPORT
statements. You will have to add some
IMPORT
statements which reflect the finer structuring of
BIBLIOTHECA OPALICA.
We will first specify the incompatibilities and then list old library structures with the changes they each require. The treatment of text is considered in a separate section.
The name of the sort has changed from bitset
to set
. The
function maxBit
no longer exists, since these sets are no longer
bounded.
The format
and scan
functions from Conversion
(which have
been relocated) formerly interpreted the backslash combinations
(\n
, \x41
, etc.)
themselves, even in strings. Since denotation
constants are interpreted differently now, this feature has been removed.
The functions ! :
basictype -> string
(where
basictype is one of bool, char, nat, int, real
) have been
replaced by ` :
basictype-> denotation
in structure
BasictypeConv
(see What's in a Name? -- Naming of Structures). So you need to
change all applications of these functions, e.g. 5!
to !(5`)
(where the first !
has origin String
) in order to get an
equivalent expression. For treatment of text, see also Treatment of Text.
denotation
Denotation constants are now interpreted in a C-like way, i.e. combinations
like \n
, \x41
, etc. are now interpreted as a single
character. The only exception is \"
, which is interpreted as end of
text. To denote a single \
, write \\
.
The constant max'Nat
was raised and is no longer convertible to an
object of type int
. Strictly speaking, this is not an
incompatibility, since this was never guaranteed, but since quite a few
people seem to have relied on this fact we record it here.
If you assumed asInt(max'Nat)
to be defined, you will get a runtime
error message which says asInt'NatConv: natural too large
. A quick
remedy is to replace occurrences of max'Nat
by asNat(max'Int)
,
but this is a little bit awkward. A better (but more time consuming)
solution is to check whether your program needs either objects of type
int
or of type nat
and to change it as required.
The structure Section
no longer exists. Use lambda expressions
instead of the functions which were supplied by Section
.
The structure Suspend
no longer exists. Use lambda expressions
instead of the functions which were supplied by Suspend
.
This section contains a list of those structures from the old library which were modified, and thus necessitate changes in your program.
Structures which are "split into" no longer exist. Structures which are marked "split off" still exist, but some functions now have to be imported from different structures.
Functions which are marked "old fashioned" in BIBLIOTHECA OPALICA are marked with (+) in the following list.
ArrayMapReduce
ArrayMap
with function *
, and ArrayReduce
with function /
.
Bag
BagFilter
with function |
, and BagConv
with
functions explode(+), implode(+), explodeCt(+), implodeCt(+)
.
Bitset
bitset
renamed set
, function maxBit
no
longer exists.
Char
CharConv
with function ord(+)
, and NatConv
with function chr(+)
.
ComData
BinStream
.
ComEnv
Env
, function random
relocated to
Random
, function localtime
will be relocated to structure
Time
.
ComProcess
Process
and
Pipe
for adapting your code.
ComSocket
Socket
.
ComStream
Stream
.
Conversion
NatConv
with function ! : nat -> string
renamed
` 'NatConv: nat -> denotation
, (similar for type int, bool,
real
and char
); into BTUnion
with type union
and
function u
; into StringFormat
with function format
and
StringScan
with function scan
.
Int
IntConv
with function asNat
, and NatConv
with
function asInt
.
Map
MapConv
with function explode(+)
and implode(+)
.
MapMapReduce
MapMap
with function *
, and MapReduce
with
function /
.
PrintableChar
_
renamed underscore
.
Real
RealConv
with function trunc(+)
, and NatConv
with function asReal
.
Section
Seq
SeqFilter
with functions |, partition, take, drop,
split
, and SeqIndex
with functions !, slice
.
SeqFun
SeqCompare
with type rel
and functions <, =,
>, <?, =?, >?, cmp
and eq?
, into SeqOfSeq
with function
flat
, and SeqSort
with functions msort
and merge
.
SeqMapReduce
SeqMap
with function *
, and SeqReduce
with
functions /, \
.
Set
SetConv
with functions explode(+)
and
implode(+)
, and SetFilter
with functions |
and
partition
.
SocketInterNet
Internet
.
String
StringConv
with functions implode(+)
and
explode(+)
, and StringIndex
with functions !, slice,
insert, delete
and :=
.
Suspend
One of the novelties in BIBLIOTHECA OPALICA is the different treatment
of the types string
and denotation
. We will discuss here why
we made this change and advise which type to choose in which circumstances.
The situation in the old library was unsatisfactory. First you had the type
denotation
, which was almost unusable, since no functions operated on
denotations (well, one did). Then there was the string
type which,
while it provided a usable interface for simple treatment of text, was not
equipped with a free type. So whenever you wrote an "interesting" function
on text, you first had to convert the string into a sequence of characters,
and, after performing two expensive conversions, you finally had access
to the nice higher-order functions like map, reduce and the like.
This has changed in BIBLIOTHECA OPALICA.
In principle, the only change you need to make is to adapt the IMPORT
lines, since all functions on strings have been retained in BIBLIOTHECA
OPALICA.
However, you should examine your code, and depending on the usage of text, choose one of the following approaches:
If you have strings that are not changed very often you should
consider changing type string
to type denotation
and
the IMPORT
line from IMPORT String ONLY
... to
IMPORT Denotation ONLY
...
The other possibility is that you are working on the text, and will
therefore perform an explode
on the text before you really start
applying functions. In this case you should replace type seq[char]
with type string
and remove the explode
and implode
function calls. You will now have to import the functions which you used on
sequences from the corresponding string structures.
When designing structures for your own data types, you should follow the principles used for structuring the library itself (see What's in a Name? -- Naming of Structures).
First have a look at the library and search for the most similar type already available. Perhaps you are missing another arithmetic type, or your new type can be considered as an aggregate type, or you want to give a different implementation for a data type which already exists.
If you find a similar data type, try to copy the interfaces of the corresponding structures as far as reasonable. If you give a different implementation for an existing data type, keep the name of the type.
If you want to define a totally new data type, you should nevertheless try
to use names from existing structures which perform a similar task. If
you somehow "select" elements, call that function !
. The
concatenation is called ++
, composition is named o
and no
doubt you will find other functions which resemble functions on the new data
type.
Always define a function ` : type -> denotation
(appropriately
augmented if the type is parameterized). There are first experimental
tools, which exploit the fact that for every type type
a conversion
function `
exists in TypeConv
.
Try to keep interfaces small. Give a base structure which contains the most necessary function declarations. Group additional functions into separate structures.
And do not forget to send us the product of your efforts if you think it fills a gap in BIBLIOTHECA OPALICA.
There are some functions in BIBLIOTHECA OPALICA which are marked "not for user purpose". The functions in these sections provide access to internal representations; these are needed for the efficient implementation of other functions on the same date type, when the data type is located in another structure.
In principle, you may use these functions as you do other functions and perhaps you gain some additional performance in doing so. You do this at your own risk, however. We do not guarantee anything about the behaviour of functions which are marked "not for user purpose"; moreover these functions are subject to change in later releases of BIBLIOTHECA OPALICA without further notice.
55 entries
[ a ] [ b ] [ c ] [ d ] [ f ] [ g ] [ h ] [ i ] [ m ] [ n ] [ o ] [ p ] [ q ] [ r ] [ s ] [ t ] [ u ] [ v ] [ w ]agent'ComAgent[result] |
array[data] |
bag[data, <] |
bool |
bstree'BSTree[data, <] |
char |
childstat'Wait |
com[data] |
denotation |
device'FileSystem |
file |
filemode'FileSystem |
filestat'FileSystem |
filetype'FileSystem |
fission'ProcessCtrl |
funct[from, to] |
group'UserAndGroup |
groupid'UserAndGroup |
heap[data, <] |
inode'FileSystem |
int |
map[dom, <, codom] |
nat |
option[data] |
pair[data1, data2] |
permission'FileSystem |
process'ProcessCtrl |
procstat'ProcessCtrl |
quad'Quadruple[data1, data2, data3, data4] |
real |
rel |
sap'ComService[in, out] |
seq[data] |
set'Bitset |
set'Set[data, <] |
set'SetByBST[data, <] |
set'SetByInj[data, #] |
set'SetByPred[data] |
sigaction'Signal |
sighandler'Signal |
sigmask'Signal |
signal |
string |
subrel |
time |
tree[data] |
triple[data1, data2, data3] |
union'BTUnion |
union'Union2[data1, data2] |
union'Union3[data1, data2, data3] |
union'Union4[data1, data2, data3, data4] |
user'UserAndGroup |
userid'UserAndGroup |
void |
wday'Time |
This document was generated 5 June 2001 (14:11:30) using the texi2html translator version 1.51-kd-pl15.