|
|
|
Reference Manual of LoI - Datatypes and Expressions |
|
|
Each expression results in a value and has a type. In the following, the different expressions are presented in clusters centering around the datatype they are connected to (for references to variables cf. 3.4 and roles cf. 3.6.3). All remaining forms of expressions, that do not fit in this scheme, will be described separatly.
Object is an abstract type for data. It is usually used to pass data from one role to another without processing the data itself.
The corresponding type is object
There is one constant which designates the empty object:
nil
Objects may be compared for equality or unequality.
<expression 1 of type object> = = <expression 2 of type object> <expression 1 of type object> ! = <expression 2 of type object>
Objects are equal if they are identical, which means that they represent the same object. Unequality is the just the negation of equality.
Values of type Void are actually used as dummy values (e.g.passing a value to a "function", which needs an argument).
The corresponding type is void.
A constant (and the only value) is defined for Void:
( )Integers are a continuous subset of the whole numbers (meaning that are no gaps in the subset). The minimum and maximum value of this subset depends on the implementation.
The corresponding type is int.
Only the positive integers can be represented (cf. 3.2.4.1). Negative integers are created using the negation operator (cf.below).
The following binary and unary operators are possible for integers (consider also the increment operator in 3.4.2.2 or the decrement operator in 3.4.2.3)
<expression 1 of type integer> + <expression 2 of type integer> <expression 1 of type integer> - <expression 2 of type integer> <expression 1 of type integer> * <expression 2 of type integer> <expression 1 of type integer> / <expression 2 of type integer> <expression 1 of type integer> % <expression 2 of type integer> - <expression of type integer> |
The operators represent addition (+), subtraction ( -, binary),
multiplication (*), division (/), remainder (%) and arithmetic negation ( -,
unary).
Division and remainder are defined as a = b*(a / b) + a % b
with 0 < a % b < b. The division and remainder are undefined
if b = 0.
Remark: an underflow or an overflow may occur if the minimal
or maximal value is passed.
The following two functions provide
conversion from strings to integers and vice versa:
|
a2i converts a number given in a decimal representation to an
integer. The result is undefined if non-decimal characters are used.
i2a converts an integer to a number in a decimal
representation.
Integers may be compared for equality or unequality.
<expression 1 of type integer> = = <expression 2 of type integer> <expression 1 of type integer> ! = <expression 2 of type integer> |
Expressions of type integer are equal if they result in the same value. Unequality is just the negation of equality.
Integers may be compared using the following operators
<expression 1 of type integer> < <expression 2 of type integer> <expression 1 of type integer> > <expression 2 of type integer> <expression 1 of type integer> <= <expression 2 of type integer> <expression 1 of type integer> >= <expression 2 of type integer> |
Each operator results in a value of type Boolean.
Floats are a subset of the rational numbers. The minimum and maximum value of this subset depends on the implementation. The same is true for the nearest (positive or negative) value to zero.
The corresponding type is float
Only positive floats can be represented (cf. 3.2.4.1). Negative floats are created using the negation operator (cf.below).
The following binary and unary operators may be used in connection with floats:
<expression 1 of type float> + <expression 2 of type float> <expression 1 of type float> - <expression 2 of type float> <expression 1 of type float> * <expression 2 of type float> <expression 1 of type float> / <expression 2 of type float> - <expression of type float> |
The operators represent addition (+), subtraction ( -, binary),
multiplication ( * ), division ( / ) and arithmetic negation ( -,
unary).
Remark: an underflow or an overflow may occur if the minimal or
maximal value is passed.
Floats may be compared for equality or unequality.
<expression 1 of type float> = = <expression 2 of type float> <expression 1 of type float> ! = <expression 2 of type float> |
Expressions of type float are equal if they result in the same value. Unequality is just the negation of equality.
Floats may be compared using the following operators
<expression 1 of type float> < <expression 2 of type float> <expression 1 of type float> > <expression 2 of type float> <expression 1 of type float> <= <expression 2 of type float> <expression 1 of type float> >= <expression 2 of type float> |
Each operator results in a value of type Boolean.
There are two conversion functions in relation to floats:
|
int2float converts the given float value into an integer value
truncating the fractional part of the float.
float2int is the opposite function: its result is the integer value
of the given value.
Both functions may be partially defined - dependent on the implementation. float truncates the fractional part of the float value.
The datatype Boolean is used in logical and relational expressions.
The corresponding type is bool
Two constants are defined
true
false
The common Boolean operators are defined: and (&&), inclusive or ( | | ), and not ( ! ).
<expression 1 of type Boolean> && <expression 2 of type integer> <expression 1 of type Boolean> || <expression 2 of type integer> ! <expression 1 of type Boolean> |
The and- and or-operator have a special (partially non-strict)
evaluation. Only the first argument is computed at the beginning, if
the result equals true (for &&) or false (for | |)
the second argument is not computed.
Boolean values may be compared for equality or unequality.
<expression 1 of type Boolean> = = <expression 2 of type Boolean> <expression 1 of type Boolean> ! = <expression 2 of type Boolean> |
Expressions of type Boolean are equal if they result in the same value. Unequality is just the negation of equality.
Values of type Char are used to represent single symbols (like A).
The corresponding type is char.
Two primitive functions are defined in relations to characters
|
ord returns the code number of the given character; chr
returns the character corresponding to the given code. chr is
undefined for values for which there is no character defined in the
underlying character set.
Characters may be compared for equality or unequality.
<expression 1 of type Char> = = <expression 2 of type Char> <expression 1 of type Char> ! = <expression 2 of type Char> |
Expressions of type Char are equal if they result in the same value. Unequality is just the negation of equality.
Characters may be compared using the following operators
<expression 1 of type char> < <expression 2 of type char> <expression 1 of type char> > <expression 2 of type char> <expression 1 of type char> <= <expression 2 of type char> <expression 1 of type char> >= <expression 2 of type char> |
Each operator results in a value of type Boolean.
Values of type Mutex are used for synchronization purposes (cf. 3.7.10). Essentially, a mutex is a simplified version of semaphores only allowing a locked and a unlocked state.
The corresponding type is mutex.
There are no constants defined for data values of type Mutex.
There is a generator function for mutex values:
make_mutex ()
This function returns a new mutex value.
Mutex values may be compared for equality or unequality.
<expression 1 of type Mutex> = = <expression 2 of type Mutex> <expression 1 of type Mutex> ! = <expression 2 of type Mutex> |
Expressions of type Mutex are equal if they result in the same mutex value. Unequality is just the negation of equality.
For the definition of a module cf. 3.3
The corresponding type is module
It is not possible to compare modules.
Values of type Port can be interpreted as instances of roles. This means, that if two messages are passed to one and the same role, the messages might arrive at different agents if the port of the role was exchanged cf. 3.7.27). What makes them a bit special, is that a port can be connected to different roles at the same time. But it is not possible to connect several ports to one and the same role. Ports are especially useful for having different sessions with regards to interactions.
The corresponding type is port.
There are no constants for ports.
One generator is defined:
make_port ()
This function generates new ports.
Cf. 3.7.27 for binding ports to roles.
Port values may be compared for equality or unequality.
<expression 1 of type Port> = = <expression 2 of type Port> <expression 1 of type Port> ! = <expression 2 of type Port> |
Expressions of type Port are equal if they result in the same port value.
Unequality is just the negation of equality.
Arrays are values that cluster values of the same type. Each component of such an array is in a unique way addressable. The addresses range between 0 and the length of the array - 1.
The corresponding type is {<component type>}
Array constants are enclosed in curly brackets and list the components of the array:
|
There is also an abbreviation for components that have the same value and are ordered one after the other:
<an expression of type t> # <an expression of type Integer>
The expression in front of the sharp character designates the component and the one after it the number of copies, that is
|
result in both cases in an array with the same content.
The components of an array may be modified or accessed. A modification is only possible in modification statements (cf. 3.7.22), which have for arrays the following forms:
<a variable>[<an expression of type Integer>] := <an expression> <a variable>[<an expression of type Integer>] ++ <a variable>[<an expression of type Integer>] - - |
Note, that the variable has to be of type Array. With regards to the
first form, the component type has to be equal with that of the
expression. In the second and third form, the component type has to be
equal to Integer. At first, the index is computed (the expression between the square
brackets), then the component is accessed using the computed index and
modified according to the given operation (assignment, increment or
decrement).
An access expression is similar:
<an expression of type Array>[<an expression of type Integer>]
First the index is computed. Then the
component is accessed and its value returned.
Remark: The operations, which have been described in the preceding
paragraphs are only valid, if the computed index is within the bounds
of the array.
The following operator generates a new array which is the concatenation of its arguments. The arrays given as arguments have to have the same component type.
<expression 1 of type Array> + <expression 2 of type Array>
The function returns the length of the given array as an integer.
length <an expression of type array>
Array values may be compared for equality or unequality.
<expression 1 of type Array> = = <expression 2 of type Array> <expression 1 of type Array> ! = <expression 2 of type Array> |
Expressions of type Array are equal if they result in the same array value, which means that the resulting array has to be identical. Unequality is just the negation of equality.
Strings are just arrays with the component type Char. Thus, all operations of arrays are also available to strings.
The corresponding type is string, which is equal to {char}.
There is special form which generates strings (cf. 3.2.4.5).
"<a sequence of characters>"
Strings may be compared using the following operators
<expression 1 of type string> < <expression 2 of type string> <expression 1 of type string> > <expression 2 of type string> <expression 1 of type string> <= <expression 2 of type string> <expression 1 of type string> >= <expression 2 of type string> |
Each operator results in a value of type Boolean.
Tuples are used to cluster entities of different type. Components
of a tuple may be labeled or unlabeled.
Remark: Two expressions of type Tuple may have different component
types, but are equal with regards to their type.
The corresponding type is
(<component type 1>, <component type 2>,....<component type n>).
Tuple constants are enclosed in parentheses and list the components of the tuple:
( <a tuple component> <a tuple component> ...., <a tuple component> ) |
Note, that a tuple must have two components at least. A component consist of an expression; optionally a label may be attached (cf.the second form):
<an expression> <an identifier> = <an expression> |
The components of a tuple may be modified or accessed. A modification is only possible in modification statements (cf. 3.7.22), which have for tuples the following forms:
<a variable> . <a integer n> := <an expression> <a variable> . <a integer n> ++ <a variable> . <a integer n> - - |
Note, that the variable has to be of type Tuple. With regards to the
first form, the component type (designated by the integer) has to be
equal with that of the expression. In the second and third form, the
component type has to be equal to Integer.
That component, which is denoted by the given integer, is modified according
to the given operation (assignment, increment or decrement).
The access operation looks like
<an expression of type Tuple> . <a integer>
That component, which is denoted by the integer, is accessed and its
value returned.
Remark: The operations, which have been described in the preceding
paragraphs are only valid, if the integer (the index) is within the bounds
of the tuple.
If a component has a label, it may also be modified as follows
<a variable> . <an identifier> := <an expression> <a variable> . <an identifier> ++ <a variable> . <an identifier> - - |
The access operation is then
<an expression of type Tuple> . <an identifier>
Tuple values may be compared for equality or unequality.
<expression 1 of type Tuple> = = <expression 2 of type Tuple> <expression 1 of type Tuple> ! = <expression 2 of type Tuple> |
Expressions of type Tuple are equal if they result in the same tuple value, which means that the resulting tuple has to be identical. Unequality is just the negation of equality.
Constructors are the labels of concrete types (Cf. 3.4.9 for the definition of a constructor function). Typically, they are used to generate a value of that type:
<a constructor> <an expression>
The expression has to be of the same type as the parameters of the
constructor.
Constructors can also be handled as separate values. This is necessary
for the identification of the components of a constructed type.
The corresponding type of a constructor is constructor The type
of the result of the constructor function depends on the definition of
the constructor.
|
The arg operator returns the argument of the constructed
type. The given constructor has to be defined for the constructed
type; otherwise the result is undefined. constructor returns the
constructor of the argument.
Examples:
|
The result of the first expression will be (1, Empty); the
second expression will evaluate to Cons.
Constructors and concrete types can be compared for equality:
<expression 1 of type constructor> = = <expression 2 of type constructor> <expression 1 of type constructor> ! = <expression 2 of type constructor> expression 1 of a concrete type> = = <expression 2 of a concrete type> expression 1 of a concrete type> ! = <expression 2 of a concrete type> |
Expressions of type constructor are equal if they result in the same value. With regards to concrete types, both arguments have to have the same constructor and argument. Unequality is just the negation of equality.
Apart from the predefined functions it is possible to define new functions.
The corresponding type is
<type of the parameters> => <result type>.
There are the predefined functions. New functions can be constructed using this forms
(<an identifier>, <an identifier>, ...., <an identifier>) =>
{ <a statement> }
<an identifier> => {<a statement>}
|
This notation is best explained together with an application:
<an expression of type t1 => t2> <an expression of type t1> |
If our function is defined in the first way, the second expression in
the application has to be a tuple with the same number of components
as the list of parameters in the definition - of cause the types of
the argument and its corresponding parameter also have to be equal.
If our function was defined in the second way, the parameter will be
bound to the result of the second expresssion of the application.
Functions may return a result (cf. 3.7.17) or not. (In the second case
they usually called procedures).
For recursive definitions it is possible to use a pseudo
variable, this. This variable refers to the most actual
function. Thus a definition of the factorial looks in LoI like that:
|
But, you can also use the name of the function itself:
|
Apart from functions already mentioned, we have
|
now returns the current time as an integer. (This might not
correspond to wall time, but we expect that successive calls to
now will never return a result that is less to a previous
result.) setseed memorizes the given integer as
a seed for pseudo-random number generation. random generates a
pseudo-random number using a seed value.
For functions concerned with threads confer 3.8
Like in 3.7.18, but the result of the function is the value of the
expression. If a module (cf. 3.5.10) is activated, the result is void.
Subexpressions are expressions that are enclosed in parentheses:
(<an expression>)
The operators and forms, which may used in expressions, have the following increasing precedence (each line represents a precedence level):
|
|
|
|
Reference Manual of LoI - Datatypes and Expressions, © 2000 by Gil Müller |
|
|