ReactiveML, a Reactive Extension to ML∗

ReactiveML, a Reactive Extension to ML∗
Louis Mandel and Marc Pouzet
Université Pierre et Marie Curie
LIP6 †
ABSTRACT
We present ReactiveML, a programming language dedicated to the implementation of complex reactive systems as
found in graphical user interfaces, video games or simulation
problems. The language is based on the reactive model introduced by Boussinot. This model combines the so-called
synchronous model found in Esterel which provides instantaneous communication and parallel composition with classical features found in asynchronous models like dynamic
creation of processes.
The language comes as a conservative extension of an existing call-by-value ML language and it provides additional
constructs for describing the temporal part of a system.
The language receives a behavioral semantics à la Esterel
and a transition semantics describing precisely the interaction between ML values and reactive constructs. It is
statically typed through a Milner type inference system and
programs are compiled into regular ML programs. The language has been used for programming several complex simulation problems (e.g., routing protocols in mobile ad-hoc
networks).
1. INTRODUCTION
Synchronous programming [4] has been introduced in the
80’s as a way to design and implement safety critical realtime systems. It is founded on the ideal zero delay model
where communications and computations are supposed to
be instantaneous. In this model, time is defined logically
as the sequence of reactions of the system to input events.
The main consequence of this model is to conciliate parallelism — allowing for a modular description of the system —
and determinism. Moreover, techniques were proposed for
this parallelism to be statically compiled, i.e, parallel programs are translated into purely sequential imperative code
†
Laboratoire d’Informatique de Paris 6, Université Pierre et
Marie Curie, 8 rue du Capitaine Scott, 75015 Paris, France.
email: {Louis.Mandel, Marc.Pouzet}@lip6.fr
∗This work is supported by the French ACI Sécurité Alidecs.
Permission to make digital or hard copies of all or part of this work for
personal or classroom use is granted without fee provided that copies are
not made or distributed for profit or commercial advantage and that copies
bear this notice and the full citation on the first page. To copy otherwise, to
republish, to post on servers or to redistribute to lists, requires prior specific
permission and/or a fee.
Copyright 200X ACM X-XXXXX-XX-X/XX/XX ...$5.00.
in terms of transition systems [5, 14].
Synchronous languages are restricted to the domain of
real-time systems and their semantics has been specifically
tuned for this purpose. In particular, they forbid important
features like recursion or dynamically allocated data in order to ensure an execution in bounded time and memory. In
the 90’s, Boussinot observed that it was possible to conciliate the basic principles of synchronous languages with the
dynamic creation of processes if the system cannot react instantaneously to the absence of an event. In this way, logical
inconsistencies which may appear during the synchronous
composition of processes disappear as well as the need of
complex causality analysis to statically reject inconsistent
programs. This model was called the synchronous reactive
model (or simply reactive) and identified inside SL [11], a
synchronous reactive calculus derived from Esterel. Later
on, the Junior [15] calculus was introduced as a way to give
a semantics to the SugarCubes [13], this last one being an
embedding of the reactive model inside Java. This model
has been used successfully for the implementation of complex interactive systems as found in graphics user interfaces,
video-games or simulation problems [12, 13, 2] and appears
as a competitive alternative to the classical thread-based
approach.
From these first experiments, several embedding of the reactive model have been developed [7, 13, 25, 27]. These implementations have been proposed in the form of libraries inside general purpose programming languages. The “library”
approach was indeed very attractive because it gives access
to all the features of the host language and it is relatively
light to implement. Nonetheless, this approach can lead to
confusions between values from the host languages used for
programming the instant and reactive constructs. This can
lead to re-entrance phenomena which are usually detected by
run-time tests. Moreover, signals in the reactive model are
subject to dynamic scoping rules, making the reasoning on
programs hard. Most importantly, implementations of the
reactive model have to compete with traditional (mostly sequential) implementation techniques of complex simulation
problems. This calls for specific compilation, optimization
and program analysis techniques which can be hardly done
with the library approach.
The approach we choose is to provide concurrency at language level. We enrich a strict ML language with new primitives for reactive programming. We separate regular ML expressions from reactive ones through the notion of a process.
An ML expression is considered to be an atomic (timeless)
computation whereas a process is a state machine whose be-
havior depends on the history of its inputs. It is made of
regular ML expressions and reactive expressions. Regular
ML expressions are executed as is without any computational impact whereas reactive expressions are compiled in
a special way. We introduce two semantics for the language.
The first one is a behavioral semantics in the style of the
logical behavioral semantics of Esterel. This semantics
defines what is a valid reaction no matter how this reaction is actually computed. In order to derive an execution
mechanism, we introduce a transition semantics and prove
it to be equivalent. Compared to existing semantics for the
reactive model (e.g., Junior), these two semantics express
precisely the interaction between values from the host language and reactive constructs and this is new. Moreover,
the language is statically typed through a Milner type system. Compared to the library approach, we believe that the
language approach leads to a safer and a more natural programming. In particular, the language provides a notion of
signals with regular scope properties. Moreover, some parts
of a program can be compiled vs interpreted, leading to a
far more efficient execution.
Section 2 illustrates the expressiveness of the language on
some simple examples. 1 A synchronous reactive calculus
based on Boussinot’s model is defined in section 3. We embed this kernel inside a call-by-value ML kernel. Section 4
presents its behavioral semantics and establish its two main
properties: in a given environment, a program is deterministic and always progress. Section 5 presents a transition
semantics and an equivalence theorem. Section 6 presents
the type system which comes as a natural extension of the
ML type system of the host language. Implementation issues are addressed in section 7. In section 8, we discuss
related works and conclude.
2. LANGUAGE OVERVIEW
2.1 A Short Introduction to ReactiveML
ReactiveML is built above Ocaml [18] such that every
Ocaml program (without objects, labels and functors) is a
valid program and ReactiveML code can be linked to any
Ocaml library.
A program is a set of definitions. Definitions introduce,
like in Ocaml, types, values or functions. ReactiveML
adds the process definition. Processes are state machines
whose behavior can be executed through several instants.
They are opposed to regular Ocaml functions which are
considered to be instantaneous. Let us consider the process hello_world that prints “hello” at the first instant and
“world” at the second one (the pause statement suspends
the execution until the next instant):
let process hello_world =
print_string "helloÃ";
pause;
print_string "world"
This process can be called by writing: run hello_world.
Communication between parallel processes is made by
broadcasting signals. A signal can be emitted (emit), awaited
(await) and we can test its presence (present). The following process emits the signal z every time x and y are
synchronous.
1
The distribution of ReactiveML and complete examples
can be found at www-spi.lip6.fr/~mandel/rml.
let process together x y z =
loop
present x then present y then (emit z; pause)
end
Unlike Esterel, it is impossible to react instantaneously to
the absence of an event. Thus, the following program:
present x then () else emit x
which is incorrect in Esterel — x cannot be present and
absent in the same instant and is thus rejected by a causality
analysis — is perfectly valid in the reactive model. In this
model, the absence of x is effective in the next instant. Thus,
the previous program is equivalent to:
pause; emit x
Now, we can write the edge front detector, a typical construct appearing in control systems. The behavior of the
process edge is to emit s_out when s_in is present and it
was absent in the previous instant.
let process edge s_in s_out =
loop
present s_in then pause
else (await immediate s_in;
emit s_out)
end
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
s_in
s_out
While s_in is present, the process emits no value. When
s_in is absent, no value is emitted at that instant and the
control passes through the else branch. At the next instant,
the process awaits for the presence of s_in. When s_in
is present then s_out is emitted (since s_in was necessary
absent at the previous instant). The immediate keywords
states that s_in is taking into account even if s_in appears
at the very first instant.
We now introduce the two main control structures of the
language: the construction do e when s suspends the execution of a process e when the signal s is absent whereas
do e until s interrupts the execution of e when s is present.
We illustrate these two constructions on a suspend_resume
process which control the instant where a process is executed.
We first define a process sustain parameterized by a signal s. sustain emits the signal s at every instant.
let process sustain s = loop emit s; pause end
We define now an other typical primitive. switch is a two
states Moore machine which is parameterized by two signals, s_in and s_out. Its behavior is to start the emission
of s_out when s_in is emitted and to sustain this emission
while s_in is absent. When s_in is emitted again, the emission of s_out is stopped and the process returns in its initial
state.
let process switch s_in s_out =
loop
await immediate s_in;
pause;
do run (sustain s_out) until s_in done
end
emit s v1
emit s v2
emit s vn
await s(x) in ...
v
f
d
signal sum default 0 gather (+) in ...
await s(y) in ...
v = (f vn ... (f v2 (f v1 d))...)
Figure 1: Multi-emission on signal s, combined with
function f, gives the value v at the next instant.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
s_in
We define now the process suspend_resume parameterized
by a signal s and a process p. This process awaits the first
emission of s to start the execution of p. Then, each emission
of s alternatively suspends the execution of p and resumes
it. We implement this process with the parallel composition
of (1) a do/when construction that executes p only when the
signal active is present and (2) the execution of a switch
that controls the emission of active with the signal s.
let process suspend_resume s p =
signal active in
do run p when active
||
run (switch s active)
Notice that suspend_resume is an example of a higher-order
process since it takes a process p as a parameter.
ReactiveML also provides valuated signals. They can
be emitted (emit signal value) or awaited to get the associated value (await signal (pattern) in expression). Different values can be emitted during an instant, it is called
multi-emission. ReactiveML adopts an original solution
for that: when a valued signal is declared, we have to define how to combine values emitted during the same instant.
This is achieved with the construction:
signal name default value gather f unction in expression
The behavior of multi-emission is illustrated in Fig. 1. We
assume signal s declared with the default value d and the
gathering function f. If values v1, ..., vn are emitted during
an instant, then all the await receive the value v at the next
instant. 2 Getting the value associated to a signal is delayed
to avoid causality problems. Indeed, as opposed to Esterel
and following the reactive approach of Boussinot, the following program await s(x) in emit s(x+1) is causal: the
integer value x of s (potentially resulting from the combination of several values) is only available at the end of the
instant. Thus, if x = 42 during the current reaction, the
program will emit s(43) in the following reaction. Notice
that this is different from awaiting the signal presence which
executes its continuation in the same instant.
The type of the emitted values and the type of the combination’s result can be different. This information is reported
in the type of signals. If τ1 is the type of the emitted values
v = (f vn ...
In this case, the program await sum(x) in print_int x
awaits the first instant in which sum is emitted and then, at
the next instant, prints the sum of the values emitted. sum
has type (int, int) event
An other very useful signal declaration is the one that
collects all the values emitted during the instant which is
written simply:
signal s in ...
as a short-cut for:
s_out
2
on a signal s and τ2 is the one of the combination, then s
has type (τ1 , τ2 ) event.
If we want to define a signal sum that computes the sum
of the emitted values, then we can write:
(f v2 (f v1 d))...)
signal s default Multiset.empty gather Multiset.add
in ...
Here, the default value is the empty set and the gathering
function, the addition of an element in a multiset. 3
2.2
The Sieve of Eratosthenes
We consider the sieve of Eratosthenes as it can be found
in [17] and is a classical in reactive calculus (see [8], for example). The Eratosthenes sieve is an interesting program
because it combines signals, synchronous parallel composition and dynamic creation.
We first write the process integers which generates the
sequence of naturals from an integer value n.
let rec process integers n s_out =
emit s_out n;
pause;
run (integers (n+1) s_out)
val integers : int -> (int, ’a) event -> process
It is a recursive process that is parameterized by an integer
n and a signal s_out. Recursive calls are made through a
run. We can notice that there is no instantaneous recursion
because of the (pause) statement. The type of the process
is inferred by the compiler.
Now, we define the process filter which removes all the
multiple of some prime number. For this purpose, we define an auxiliary function not_multiple. not_multiple is
a regular Ocaml function which can be used in any other
Ocaml expression or reactive process.
let not_multiple n p = n mod p <> 0
val not_multiple : int -> int -> bool
let process filter prime s_in s_out =
loop
await s_in(n) in
if not_multiple n prime then emit s_out n
end
val filter : int -> (’a, int) event ->
(int, ’b) event -> process
It is an error to write a reactive construction (such as pause)
in a regular Ocaml expression and the compiler rejects it.
For example the function let f x = pause; x is rejected.
3
In the actual implementation, emitted values are gathered
in a list.
Now, the process shift creates a new filter process
for each newly discovered prime number. We can notice
that dynamic creation is done through recursion. Therefore, as opposed to conventional synchronous programming
languages, ReactiveML does not ensure an execution in
bounded time and memory but this is not a surprise.
let rec process shift s_in s_out =
await s_in(prime) in
emit s_out prime; (* emit a discovered prime *)
signal s default 0 gather fun x y -> x in
run (filter prime s_in s) || run (shift s s_out)
val shift :
(int, int) event -> (int, ’a) event -> process
Finally, we define the process output which prints the
prime numbers and the main process sieve.
We introduce a reactive kernel in which programs given
in the introduction can be translated easily. 4 This kernel is
built above a call-by-value functional language with an ML
syntax. Expressions (e) are made of variables (x), immediate constants (c), pairs (e, e), abstractions (λx.e), applications (e e), local definitions (let x = e in e), recursions
(rec x = e), processes (proc e), a sequence (e;e), a parallel
synchronous composition of two expressions (e||e), a loop
(loop e), a signal declaration (signal x default e gather e in e)
with a default value e1 and a combination function e2 , a
test of presence (present e then e else e), an emission
of a valued signal (emit e e), an instantiation of a process
definition (run e), a preemption (do e until e), a suspension (do e when e) and the access to the value of a signal
let e(x) in e.
let process output s_in =
loop await s_in (prime) in print_int prime end
val output : (’a, int) event -> process
let process sieve =
signal nat default 0 gather fun x y -> x in
signal prime default 0 gather fun x y -> x in
run (integers 2 nat)
||
run (shift nat prime)
||
run (output prime)
val sieve : process
The gathering functions of the signals nat and prime keep
only one of the emitted values.
2.3 Higher Order and Scope Extrusion
We present now an example where processes are emitted
on signals. We encode the construction Jr.Dynapar("add",
Jr.Halt()) of Junior introduced in [1] for the programming
of Agent systems. This process receives some processes on
the signal add and executes them in parallel.
let rec process dynapar add =
await add (p) in
run p || run (dynapar add)
The emission of processes with free signals can lead to a
scope-extrusion problem, a classical phenomenon in process
calculi [22]. It can be illustrated on the typical example of
a process which emits a process p1 and awaits an acknowledgment of its execution in order to execute a process p2.
let process send add p1 p2 =
signal ack in
emit add (process (run p1; emit ack));
await immediate ack;
run p2
The expression process (run p1; emit ack) is the definition of an anonymous process that executes p1 and emits
ack. In this process, the signal ack is free when it is emitted
on add. ack is a local signal and add has a bigger scope, so
ack escapes its scope.
3. A SYNCHRONOUS REACTIVE CALCULUS IN ML
e
::=
c
::=
x | c | (e, e) | λx.e | e e | rec x = e | proc e
| e;e | e||e | loop e | present e then e else e
| signal x default e gather e in e | emit e e
| let x = e in e | let e(x) in e | run e
| do e until e | do e when e
true | false | () | 0 | . . . | + | - | . . .
In order to separate regular ML programs from reactive constructs, expressions (e) must verify some well formation rules
given figure 2. For this purpose, we define the predicate
k ` e where e is an expression and k ∈ {0, 1}. We shall
say that an expression e is instantaneous (or combinatorial)
when 0 ` e can be derived whereas 1 ` e means that e is reactive (or sequential to follow classical circuit terminology).
A sequential expression is supposed to take time. The rules
are defined figure 2.
A rule given in the context k (k ` e) is a short-cut for
the two rules 0 ` e and 1 ` e. So, for example, it means
that a variable or a constant can be used in any context. An
abstraction (λx.e) can also be used in an instantaneous expression or in a process but its body must be combinatorial.
For a process definition (proc e) the body is typed with the
context 1. All the ML expressions are well formed in any
context and the expressions like run, loop, or present can
be used only in a process. We can notice that there is no
rules which conclude that an expression is well formed only
in a context 0. Hence, all the combinatorial expressions can
be used in a process.
This rules implies some choices in the design of the language. For example, we could allow reactive expressions to
appear in a pair, and thus write:
k ` e1
k ` e2
k ` (e1 , e2 )
but in this case, the expression (emit s, pause) may have
several semantics. If the evaluation order is from left to
right, the signal s is emitted during the first instant while
with an evaluation order from right to left the signal is emitted at the second instant. An other choice is to execute both
expressions in parallel. We found it more clear to forbid the
use of reactive expressions in a pair such that the evaluation
order does not matter. A pair will only compose instantaneous computations.
4
For example, the definition let process f x = e1 in e2 is a
short-cut for let f = λx.proc e1 in e2 and let f x = e1 in e2
stands for let f = λx.e1 in e2 .
k`x
k`c
0`e
1`e
0 ` e1 0 ` e2
0 ` e1 0 ` e2
0 ` e1 k ` e2
0`e
k ` λx.e
k ` proc e
k ` e 1 e2
k ` (e1 , e2 )
k ` let x = e1 in e2
1 ` run e
1`e
0 ` e1 0 ` e2
0`e
1 ` e1 1 ` e2
k ` e1 k ` e2
0 ` e 1 ` e 1 1 ` e2
1 ` loop e
1 ` emit e1 e2
k ` rec x = e
1 ` e1 ||e2
k ` e1 ;e2
1 ` present e then e1 else e2
0 ` e1
0 ` e1 0 ` e2 1 ` e
0 ` e1 1 ` e2
1 ` signal x default e1 gather e2 in e
1 ` let e1 (x) in e2
1 ` e2
1 ` do e2 until e1
0 ` e1
1 ` e2
1 ` do e2 when e1
Figure 2: Well formation rules
This is essentially a two-level language, separating regular
ML expressions used for describing instantaneous computations and reactive constructs for describing the reactive part
of a system. In this way, regular ML program shall be executed as is without any computational impact whereas reactive programs will be treated specially. Compilation issues
will be discussed in section 7.
Using this kernel, we can derive other operators like the
following:
emit e
present e1 then e2
present e1 else e2
signal s in e
pause
await immediate s
await s
await s(x) in e
def
=
def
=
def
=
def
=
def
=
def
=
def
=
def
=
emit e ()
present e1 then e2 else ()
present e1 then () else e2
signal s default ∅
gather λx.λy.{x} ] y in e
signal x in present x else ()
do () when s
pause;await immediate s
await immediate s;let s(x) in e
In ReactiveML, signals are always valued. Thus, a pure
signal (in the Esterel sense) is implemented with a valued
signal with value (). At the declaration point of a signal,
the programmer must provide a default value e1 and corresponding to the instants where the signal is not emitted
and a combination function e2 . This combination function
is used to combine all the values emitted during the same
reaction. The construction signal s in p is a shortcut for
the signal declaration that collects all the values emitted
in a multiset. ∅ stands for an empty multiset and ] is
the union (if m1 = {v1 , ..., vn } and m2 = {v10 , ..., vk0 } then
m1 ] m2 = {v1 , ..., vn , v10 , ..., vk0 }).
The pause statement stops the execution for one instant.
Indeed, as opposed to Esterel and following SL [11], the
absence of a signal can only be decided at the end of the current reaction. Since x is not emitted, present x will evaluate
to false at the end of the reaction so the instruction () will
be executed during the next reaction. The await/immediate
constructs awaits for the presence of a signal. Awaiting a
valued signal can be written await s(x) in e. The access
construction let s(x) in e awaits for the end of the instant
to get the value transmitted on the signal s and starts the
execution of e on the next instant. When s is not emitted,
x takes the default value of s.
4. BEHAVIORAL SEMANTICS
In this section we formalize the execution of a Reac-
tiveML program. We base it on a behavioral semantics, in
the style of the logical behavioral semantics of Esterel [5].
We define the semantics in two steps. We defines the semantics of instantaneous computations (for which 0 ` e)
before giving the semantics of sequential computations. Notice that sequential does not mean imperative but it is used
like in the circuit terminology. An expression is sequential
when its execution can take several instants.
4.1
Instantaneous Computations
Instantaneous expressions (such that 0 ` e) are regular
ML expression which receive a standard operational semantics. For this purpose, we define the set of values (v) such
that:
v
::=
c | n | (v, v) | λx.e | proc e
A value can be an immediate constant (c), a signal value n
(belonging to a numerable set N ), an abstraction (λx.e) or
a value process (proc e).
For every instantaneous expression e, we define the predicate e ⇓ v stating that e evaluates to the value v. We use
the notation e[x ← v] for the substitution of x by v in the
expression e.
v⇓v
e1 ⇓ v 1 e2 ⇓ v 2
e[x ← rec x = e] ⇓ v
(e1 , e2 ) ⇓ (v1 , v2 )
rec x = e ⇓ v
e1 ⇓ λx.e e2 ⇓ v2 e[x ← v2 ] ⇓ v
e1 ⇓ v1 e2 [x ← v1 ] ⇓ v
e1 e2 ⇓ v
let x = e1 in e2 ⇓ v
4.2
Sequential Computations
The behavioral semantics describes the reaction of a expression to some input signal. We start with some auxiliary
definitions.
Let N , a numerable set of names and N1 ⊆ N , N2 ⊆ N .
The composition N1 .N2 is the union of the two set and is
defined only if N1 ∩ N2 = ∅.
A signal environment S is a function:
S
::=
[(d1 , g1 , m1 )/n1 , ..., (dk , gk , mk )/nk ]
A name ni is associated to a triple (di , gi , mi ) where di
stands for the default value of ni , gi stands for a combination
function and mi is the multiset of values emitted during a
reaction. If S(ni ) = (di , gi , mi ), we shall write S d (ni ) = di ,
S g (ni ) = gi and S v (ni ) = mi .
We use the notation (n ∈ S) when the signal n is present
(that is, S v (n) 6= ∅) and (n 6∈ S) when the signal is absent
(that is, S v (n) = ∅).
An event E is a function from names to multisets of values.
E
::=
[m1 /n1 , ..., mk /nk ]
We take the convention that if n 6∈ Dom(E) then E(n) = ∅.
We define the union of two events E1 , E2 as the event E =
E1 t E2 such that:
∀n ∈ Dom(E1 ) ∪ Dom(E2 ) : E(n) = E1 (n) ] E2 (n)
And E = E1 u E2 is the intersection of E1 and E2 :
∀n ∈ Dom(E1 ) ∪ Dom(E2 ) : E(n) = E1 (n) ∩ E2 (n)
The + operator adds a value v to the multiset of values
associated to a signal n in a signal environment S.

S(n0 )
if n0 6= n
(S+[v/n])(n0 ) =
(S d (n), S g (n), S v (n) ] {v}) if n0 = n
And we define the order relation v on events and lift it to
signal environments:
E1 v E 2
S1 v S 2
iff
iff
∀n ∈ Dom(E1 ) : E1 (n) ⊆ E2 (n)
S1v v S2v
The reaction of an expression e into e0 is defined in a
transition relation of the form:
E, b
N ` e −−→ e0
S
N stands for a set of fresh signal names, S stands for a signal
environment containing input, output and local signals and
E is the event made of signals emitted during the reaction.
b is a boolean value which is true if e0 has finished.
The execution of the program is a succession of reactions
(potentially infinite). The execution is finished when the
termination status b is true. At each instant, the program
reads some inputs (Ii ) and produces some outputs (Oi ) (and
local signals). The execution of an instant is defined by the
smallest signal environment Si (for the order v) such that:
E ,b
Ni ` ei −−i−→ e0i
Si
where:
Oi v Ei , and (Ii t Ei ) v Siv
g
d
Sid ⊆ Si+1
and Sig ⊆ Si+1
∀n ∈ Ni+1 .n 6∈ Dom(Si )
The smallest Si denotes the signal environment in which the
number of present signals is the smallest. This set contains
input as well as output signals (this is the property of instantaneous broadcasting of events, that is, all the emitted
signal are seen during the current reaction). The conditions
g
d
Sid ⊆ Si+1
and Sig ⊆ Si+1
mean that the default value and
gathering function associated to a signal stay the same during several reactions. We can notice that it is only necessary
to keep this information for signals which are still alive at
the end of the reaction (they do appear in e0i ). The condition ∀n ∈ Ni+1 .n 6∈ Dom(Si ) means that Ni is a set of fresh
names.
The behavioral semantics is defined in figure 3. Let us
comment the rules.
• The behavior of the parallel composition is to execute
e1 and e2 and to terminate when both branches have
terminated
• The loop is defined by unfolding. The termination
status false guaranty that there is no instantaneous
loop.
• signal x default e1 gather e2 in e declare a new signal. The default value (e1 ) and the gathering function
(e2 ) associated to x are evaluated at the signal declaration. The name x is substituted by a fresh name n
in e.
• emit e1 e2 evaluates e1 into a signal n and adds the
result of the evaluation of e2 to the multiset of emitted
values on n.
• let e(x) in e1 is used to get the value associated to a
signal. e must be evaluated in a signal n and v is the
combination of all the values emitted on n during the
instant. The function fold is defined as follows:
f old f ({v1 } ] m) v2
f old f ∅ v
= f old f m (f v1 v2 )
= v
The reaction of the program substitutes x by v in e1 .
The body is executed at the next instant. This instruction takes one instant because, in the reactive approach, all the emitted signal are known at the end of
instant only.
• let x = e1 in e2 evaluates e1 into v and substitutes x
by v in e2 . Then it evaluates e2 .
• The unit expression (()) does nothing and terminates
instantaneously.
• In a present test, if the signal is present the then
branch is executed in the instant, otherwise the else
branch is executed at the next instant.
• The do/when corresponds to the suspend construction
of Esterel. The difference is that the suspension is
not made on the presence of a signal but on the absence. This is due to the reactive approach: the reaction of a signal cannot depend instantaneously on the
absence of a signal.
• The behavior of do/until is the same as the kill of
SL. This is a weak preemption that takes one instant.
Indeed, we cannot have strong preemption to avoid
causality problems. For example with a strong preemption the following expression is not causal:
do await s until s done; emit s.
• run e evaluates the expression e into a process definition and executes it.
Now, we establish the main properties of the behavioral
semantics stating that the reaction is deterministic: for a
given signal environment there is only one way a program
can react. And if a program is reactive [5] (there exists one S
E, b
• The rules for the sequence illustrate the use of the
termination status b. The expression e2 is executed
only if e1 terminates instantaneously (b = true).
such that N ` e −−→ e0 ), then there exists a unique smallest
S
signal environment in which it can react. The proofs are
given in appendix A.
E , false
N ` e1 −−1−−−→ e01
E1 , false
N ` e1 ;e2 −−−−−→
S
E , true
E ,b
S
S
E1 tE2 , b
e01 ;e2
N1 · N2 ` e1 ;e2 −−−−−−→
S
E, false
N ` e −−−−→ e0
e1 ⇓ v 1
S
E, false
e⇓n
n∈S
S
e⇓n
n∈S
∅, false
S
E, false
N ` e1 −−−−→ e01
e⇓n
S
N ` do e1 when e −−−−→ do e01 when n
S
E, b
e⇓n
S
E, b
n 6∈ S
E, b
N ` e1 −−→ e01
N ` do e1 until e −−→ ()
N ` do e1 until e −−→ do
S
S
e01
n∈S
E, true
N ` e1 −−−−→ e01
S
E, true
N ` do e1 when e −−−−→ ()
S
e ⇓ proc e1
S
E, b
n 6∈ S
∅ ` present e then e1 else e2 −−−−→ e2
E, false
N ` e1 −−→ e01
S
N ` let x = e1 in e2 −−→ e02
S
e⇓n
S
E, b
N ` e2 [x ← v] −−→ e02
E, b
S
∅ ` do e1 when e −−−−→ do e1 when n
S
0
E, b
N ` e1 −−→ e01
E, b
∅, false
e⇓n
n∈S
N ` present e then e1 else e2 −−→ e01
n 6∈ S
E, b
N ` e[x ← n] −−→ e0
e1 ⇓ v
v = fold g m d
S
e⇓n
S
S(n) = (d, g, m)
∅ ` let e(x) in e1 −−−−→ e1 [x ← v]
S
∅, true
S g (n) = v2
∅, false
∅ ` emit e1 e2 −−−−−−−−→ ()
∅ ` () −−−−→ ()
S
S
e⇓n
[{v}/n], true
N1 · N2 ` e1 ||e2 −−−−−−−−−→ e01 ||e02
N.[n] ` signal x default e1 gather e2 in e −−→ e
S
e2 ⇓ v
S
E1 tE2 , b1 ∧b2
e02
S d (n) = v1
e2 ⇓ v 2
E ,b
2
e02
N2 ` e2 −−2−−→
S
E, b
0
N ` loop e −−−−→ e ;loop e
e1 ⇓ n
E ,b
1
e01
N1 ` e1 −−1−−→
N1 ` e1 −−1−−−→ e01 N2 ` e2 −−2−→ e02
S
E, b
N ` e1 −−→ e01
S
E, b
N ` run e −−→
until n
S
e01
Figure 3: Behavioral Semantics
The combination of this properties insures that every reactive programs can be executed in ReactiveML. Notice,
this property is not verified a priori in Esterel and needs
a causality analysis.
Lemma 1. For every expression e, the behavioral semantics of e is deterministic, i.e:
∀e, ∀S, ∀N :
if ∀n ∈ Dom(S) : S g (n) = f and f (x, f (y, z)) = f (y, f (x, z))
E ,b
E ,b
S
S
these environments. This lemma is based on the absence of
instantaneous reaction to the absence of a signal. Indeed
contrary to Esterel the absence of a signal can not generate the emission of other signals. For example, in Esterel,
the following program emits s2 if s1 is absent, but in ReactiveML the emission of s2 is delayed to the next instant
such that the absence can emit signals during the instant:
present s1 then () else emit s2.
E ,b
1
Lemma 3. Let S1 , S2 , S3 and e such that N1 ` e −−1−−→
1
2
e01 and N ` e −−2−−→
e02
and N ` e −−1−−→
then (E1 = E2 ∧ b1 = b2 ∧ e01 = e02 )
S1
E ,b
2
e1 and N2 ` e −−2−−→
e2 and S3v = S1v u S2v then there
S2
The associativity and commutativity of the gathering function expresses the fact that the order of emissions during an
instant is not specified. It is a strong constraint. But even
if it is not satisfied a program can be deterministic. For example if there is no multi-emissions the gathering function
does not have to be associative and commutative.
Lemma 2. For every expression e, let S such that
n
o
E, b
S = S | ∃E, N, b : N ` e −−→ e0
S
then there exists a (unique) smallest signal environment (uS)
such that
E, b
∃E, N, b : N ` e −−→ e0
uS
The proof of this lemma is based on the following lemma
which states that if an expression can react in two different environments then it can react in the intersection of
E ,b
3
e3 and
exists E3 , N3 , b3 and e3 such that N3 ` e −−3−−→
S3
b3 ⇒ (b1 ∧ b2 ) and E3 v (E1 u E2 ) and N3 ⊆ (N1 ∩ N2 ).
5.
OPERATIONAL SEMANTICS
The previous semantics is not operational since it express
what the reaction should verify and not how reactions are
computed. In particular, the signal environment has to be
guessed. We present now a small step semantics where the
reaction build the signal environment. An instant is made
into two steps. The first one is an extension of the reduction
semantics of ML. The second one, name the end of instant’s
reaction, prepares the next instant’s reaction.
5.1
Reduction Semantics
The reaction of an instant starts with a sequence of reactions of the form:
e/S → e0 /S 0
Contrary to the previous semantics, the signal environment
S is built during the reaction.
To define the reaction →, we start with the axioms for
²
the relation of head reduction (→
− ) figure 4.
• The let’s axiom substitutes x by v in e.
• The rule of the sequence remove the left branch when
this is a value.
• When the two branches of a parallel are values, the
parallel is reduced into the value ().
• The loop duplicates its body.
5.2
End of Instant’s Reaction
The reactive model is based on the absence of instantaneous reaction to the absence of a signal such that the treatment of the absence to prepare the reaction for the next
instant can only be done at the end of instant.
The reaction of an instant is stopped when there is no
more → reductions possible. From this point, the signal environment cannot change, there is no more signal emission.
So, all the signals not emitted are consider to be absent.
The rules for the end of instant’s reaction are of the form:
S ` e →eoi e0 and are defined figure 5. We can notice
that the rules are not given for all the expressions because
they are applied only when the program cannot be reduced
with →. Let’s comment the rules of figure 5:
• The run instruction applied to a process definition executes it.
• Values do not change at the end of an instant.
• emit n v is reduced into () and adds v to the multiset
of values emitted on n.
• The reaction of the parallel composition is the reaction
of the two branches.
• The present construction can be reduced only if the
signal is present in the environment.
• Only the left branch of the sequence reacts because the
right branch is not activated during the instant.
• The declaration of a signal x substitutes x by n in e.
n is a fresh name taken in N . n is added to the signal
environment with the default value v1 and the gathering function v2 . Initially, the multiset of values associated to n is empty.
• If there is a present instruction, the signal is considered to be absent. So the else branch has to be
executed at the next instant.
• When the body of a do/until construct is a value, it
means that it reaction is finished. So, the do/until
can be reduced into ().
• The do/when can be reduced into () only when its
body is a value and when the signal is present.
From this axioms, we define the reduction →:
²
e/S →
− e0 /S 0
0
Γ(e)/S → Γ(e )/S
n∈S
env ⇓ v
0
Γ(env )/S → Γ(v)/S
e/S → e0 /S 0
Γ(do e when n)/S → Γ(do e0 when n)/S 0
where Γ is a context with one hole. With the first rule, if
an expression e head reduces to e0 , then e can be reduced
in any context. The second rule defines the execution of
combinatorial expressions. env must be an expression which
is not a value to avoid infinite reductions. The last rule is
the suspension. The body of a do/when can be executed
only if the signal is present.
The contexts are defined as follow:
Γ
::=
[ ] | let x = Γ in e | Γ;e
| Γ||e | e||Γ | run Γ | emit Γ e | emit e Γ
| let Γ(x) in e | present Γ then e else e
| signal x default Γ gather e in e
| signal x default e gather Γ in e
| do e until Γ | do Γ until n | do e when Γ
The contexts for the parallel composition show that the evaluation order is not specified. In the implementation of ReactiveML, the scheduling is fixed such that the execution
is always deterministic but this is not specified.
• The let n(x) in e gets the values associated to the signal n and combines them with the function fold g m d
to obtain the value v. Then x is substituted by v in
e for the next instant. If n has not been emitted v is
equal to d
• The preemption occurs at the end of instant. If the
signal that control the do/until is present, the expression has to be preempted. In this case, the do/until
is rewritten into ().
• For the do/when, if the signal is present then the body
must be activated at the end of instant. If the signal
is absent, the body is not activated because it has not
been activated during the instant.
5.3
Execution of a Program
The reaction of an instant is defined by the relation:
ei /Si ⇒ e0i /Si0
If we note Ii the inputs of the reaction and Oi the outputs,
the signal environment have the following properties. All the
signals that are not in Ii are initially absent (Siv = Ii ). The
outputs are a subset of the signal environment at the end of
the reaction (Oi v Si0 ). The default values and the gathering
d
functions are kept for an instant to the other (Si0d ⊆ Si+1
0g
g
and Si ⊆ Si+1 ).
The execution of an instant is made of two steps. The
reduction of ei until a fix point is reached. Then there is the
end of instant’s reaction.
ei /Si ,→ e00i /Si0
Si0 ` e00i →eoi e0i
ei /Si ⇒ e0i /Si0
Where e/S ,→ e0 /S 0 if e/S →∗ e0 /S 0 and e0 /S 0 6→. The
relation →∗ is the reflexive and transitive closure of →.
²
let x = v in e/S →
− e[x ← v]/S
²
²
²
v;e/S →
− e/S
²
run (proc e)/S →
− e/S
²
v1 ||v2 /S →
− ()/S
loop e/S →
− e;loop e/S
²
emit n v/S →
− ()/S + [v/n]
present n then e1 else e2 /S →
− e1 /S if n ∈ S
²
signal x default v1 gather v2 in e/S →
− e[x ← n]/S[(v1 , v2 , ∅)/n] if n 6∈ Dom(S)
²
²
do v until n/S →
− ()/S
do v when n/S →
− ()/S if n ∈ S
Figure 4: Head reduction
S ` e1 →eoi e01
S ` e1 ||e2 →eoi e01 ||e02
S ` v →eoi v
n 6∈ S
S(n) = (d, g, m)
S ` present n then e1 else e2 →eoi e2
S ` e1 ;e2 →eoi e01 ;e2
n 6∈ S
v = fold g m d
n∈S
S ` e →eoi e0
S ` do e until n →eoi do e0 until n
S ` let n(x) in e →eoi e[x ← v]
n∈S
S ` do e until n →eoi ()
S ` e1 →eoi e01
S ` e2 →eoi e02
S ` e →eoi e0
n 6∈ S
0
S ` do e when n →eoi do e when n
S ` do e when n →eoi do e when n
Figure 5: End of instant
5.4 Equivalence
In this section we show the equivalence between the two
semantics.
We start with the proof that if an expression e reacts
into an expression e0 with the small step semantics then it
can react in the same signal environment with the big step
semantics.
Lemma 4. For every Sinit and e such that e/Sinit ⇒ e0 /S
Proof. The proof is made into two parts. First we prove
²
the same property for the →
− reduction. Then we show that
this is true in any context.
Now the following lemma shows that if an expression can
react with the two semantics then the signal environment
and the expression obtained at the end of the reaction are
the same.
E, b
then there exists N , b such that N ` e −−→ e0 with E =
Lemma 7. For every Sinit and e such that:
S
v
S v \Sinit
.
Proof. By induction on the number of → reductions in
e/Sinit ⇒ e0 /S.
E ,b
1
• N1 ` e −−1−−→
e1 where S1 is the small signal environ-
S1
ment such that Sinit v S1
• If there is no → reduction possible, we have to prove
that the reduction →eoi is the same that the big step
semantics (cf. lemma 5).
• If there is at least one → reduction, we have to prove
that one → reduction followed by a big step reaction
is equivalent to one big step reaction (cf. lemma 6).
The proof is based on the following properties:
Lemma 5. If e/S 6→ and S ` e →eoi e0 then there exists
∅, b
N and b such that N ` e −−→ e0 .
S
Proof. The proof is made by structural induction. We
have just to notice that if an expression e reacts with the
big step semantics into e0 and the termination status is true
E, true
(N ` e −−−−→ e0 ) then e0 behaves as () (∀N 0 , S 0 . N 0 `
S
∅, true
e0 −−−0−→ e0 ).
S
E0 , b
Lemma 6. If e/S0 → e1 /S1 and N ` e1 −−−→ e0 with
S
E, b
S1 v S then N ` e −−→ e0 with E = E 0 t (S1v \S0v )
S
• e/Sinit ⇒ e2 /S2
• ∀n ∈ Dom(S2 ) : S2g (n) = f and f (x, f (y, z)) = f (y, f (x, z)),
then e1 = e2 and S1 = S2
Proof. With lemma 4, there exists N2 , E2 and b2 such
E , b2
e2 and we can notice, by construction,
that N2 ` e −−2−−→
S2
S2 is the smallest signal environment such that Sinit v S2 .
N1 and N2 are the sets of fresh names use during the
reactions. With some renaming, we can have a set N such
E , b2
E , b1
e2 .
that N ` e −−1−−→
e1 and N ` e −−2−−→
S1
S2
With lemma 2, we know that there is a unique smallest
signal environment in which an expression can react with the
big step semantics so S1 = S2 . Now with the determinism
(lemma 1) we have E1 = E2 , b1 = b2 and e1 = e2 .
The details of the proofs are given in an extended version
of the paper [20]. 5
5
It is available at www-spi.lip6.fr/~mandel/rml.
6. STATIC TYPING
reactive construction is translated into a combinator defined
in Ocaml. Reactive programs can finally be executed by
We provide a type system as a conservative extension of
linking them with an ad-hoc Ocaml library.
the Milner type system of ML [21]. In doing so, we have
As opposed to classical synchronous programs, reactive
to deal with signals and in particular values which can be
programs
are no more statically scheduled. Programs are
transmitted on signals. The type language is:
rather scheduled dynamically or interpreted according to the
σ ::= ∀α1 , . . . , αn .τ
actual dependences between instructions reading or emitting
τ ::= T | α | τ → τ | τ × τ | process | (τ, τ ) event
signals in the programs. The scheduling strategy we have
T ::= int | bool | . . .
implemented is a greedy strategy reminiscent to a technique
introduced by Hazard 6 , known as one of the most efficient
Types are separated in regular types (τ ) and type schemes
scheduling technique for Junior. The precise description
(σ). A type (τ ) may be a basic type (T ), a type variable (α),
of the scheduling technique we have implemented in Reaca function type (τ1 → τ2 ), a product type (τ1 × τ2 ) or a protiveML is outside the scope of this paper. Let us give an
cess type (process) or the type of a signal ((τ1 , τ2 ) event).
intuitive presentation.
In the type of a signal, τ1 is the type of the emitted value
The scheduling is based on the use of waiting queues such
and τ2 is the type of the read value (obtained after collecting
that an action is fired only when the signal it is waiting for is
all the emitted values during an instant).
emitted. During the execution, the interpreter keeps track
A typing environment H has the following form:
of the set W of actions waiting for the presence of a signal
H ::= [x1 : σ1 ; . . . ; xk : σk ]
during one instant. When W is not empty at the end of the
instant, pertinent informations are transfered to the next
The instantiation and generalization is defined like the
instant.
following:
In order to implement a greedy scheduling technique, we
0
τ [τ1 /α1 , . . . , τn /αn ] ≤ ∀α1 , . . . , αk .τ
associate two waiting queues for every signal. One queue is
Gen(τ, H) = ∀α1 , ..., αn .τ
used for instructions waiting only one instant (e.g., present)
where {α1 , ..., αk } = F V (τ ) − F V (H)
and the other queue is used for instructions that can wait for
more than one instant (e.g., do/when). Thus, if the execution
Expressions are typed in an initial typing environment T C
of some code is stopped on the test of a signal then the code
such that:
to be executed is recorded in the appropriate waiting queue.
T C = [true : bool; fst : ∀α, β. α × β → α; ...]
Otherwise, its continuations are put in the set of actions
to be executed in the current instant (C). Therefore the
Expressions are typed by asserting the judgment H ` e : τ
execution of an instant consists in the execution of all the
which states that the expression e has type τ in the typing
ready actions of C. The end of the instant is decided when
environment H. The predicate is defined in figure 6.
C is empty. Instructions which are in the short-term waiting
The typing rules for ML expressions are not modified. In
queues can be treated to prepare the next instant.
the typing of signal, the default value (e1 ) has the type
With this scheduling strategy, a fast access to signals (for
of the associated value and the gathering function (e2 ) is a
presence information and waiting queues) is crucial in order
function of an emitted value and of the combination of the
to obtain an efficient execution of programs. Almost all imprevious emitted values and returns the new combination.
plementations of the reactive approach use dedicated hash
The rule for emit checks that the first argument has a signal
tables during the execution for representing the signal envitype, and that the first parameter of this type and the type
ronment. In our implementation signals are represented as
of the value emitted are the same. let e1 (x) in e gets the
regular values which are automatically garbage collected by
value associated to a signal. So, if e1 has type (τ, τ 0 ) event,
Ocaml when possible. Moreover, the presence information
x must have type τ 0 . The instantiation run e is applied to a
and associated waiting queues is done in constant time. The
process. Finally, the present, until and when constructions
efficient representation of signals together with the absence
can be applied to any signal.
of busy waiting during the execution are central in order to
The safety of the type system is proved with standard
be able to program real-size problems.
techniques [24].
Several applications have been written in ReactiveML,
7. IMPLEMENTATION AND EXPERIMENTS ranging from simple graphical systems to complex simulation problems. In particular, we have rewritten classical celWe followed a very pragmatic approach in the design of
lular automata programs written in Loft by Boussinot [10]
the language and efficiency was one of our major concern.
to serve as benchmarks for testing the efficiency of our imWe built ReactiveML as an extension of a subset of Ocaml [18]
plementation. This example puts emphasis on the absence
(without objects, labels and functors) which can mix reacof busy waiting. Quiescent cells are stopped on the waittive processes and regular Ocaml expressions. We choose
ing of an activation signal such that only active cells are
Ocaml with the following idea in mind: Ocaml will provide
executed. Figure 7 compares the execution times given for
modular data and control structures for programming the
Loft, ReactiveML and an imperative version written in
algorithmic part of the system whereas reactive constructs
Ocaml. The imperative version scans the array of cells
will provide modular control structures for describing the
with for loops. The numbers show that the implementation
temporal aspect. The compilation of a ReactiveML proof ReactiveML compete favorably with the Loft library
gram processes as follows: programs are first typed before
being translated into Ocaml code. This code can in turn
6
Through being well known in the synchronous community,
be linked with other ReactiveML programs or Ocaml lithis technique has unfortunately never been published so far
braries. This translation leaves unchanged regular ML exand can only be appreciated through a careful reading of the
pressions (only the type information is used) whereas every
code.
τ ≤ H(x)
τ ≤ T C(c)
H`x:τ
H`c:τ
H ` e 1 : τ1 → τ 2
H[x : τ1 ] ` e : τ2
H ` e 2 : τ2
H ` e 1 : τ1
H ` e 2 : τ1
H ` e 2 : τ2
H ` e1 ||e2 : unit
H ` e 2 : τ1 → τ 2 → τ 2
H ` e : unit
H ` e : process
H ` proc e : process
H ` run e : unit
H`e:τ
H ` e1 : (τ1 , τ2 ) event
H ` loop e : unit
H[s : (τ1 , τ2 ) event] ` e : τ
H ` e1 : τ
H ` e2 : τ
H ` present e then e1 else e2 : τ
H ` e 2 : τ1
H ` emit e1 e2 : unit
H ` e1 : (τ1 , τ2 ) event
H ` signal s default e1 gather e2 in e : τ
H ` e : (τ, τ 0 ) event
H[x : Gen(τ1 , H)] ` e2 : τ2
H ` let x = e1 in e2 : τ2
H ` e 1 e2 : τ2
H ` e1 ;e2 : τ2
H ` e 1 : τ2
H ` e 1 : τ1
H ` e 2 : τ2
H ` (e1 , e2 ) : τ1 × τ2
H ` λx.e : τ1 → τ2
H ` e 1 : τ1
H ` e 1 : τ1
H[x : τ2 ] ` e : τ
H ` let e1 (x) in e : τ
H ` e1 : (τ1 , τ2 ) event
H`e:τ
H ` e1 : (τ1 , τ2 ) event
H ` do e until e1 : unit
H`e:τ
H ` do e when e1 : unit
Figure 6: The Type System
% of active cells
Ocaml
Loft
ReactiveML
0%
0.74 s
0.02 s
0.05 s
4%
0.75 s
0.11 s
0.08 s
42 %
0.76 s
0.93 s
0.89 s
60 %
0.77 s
1.57 s
1.46 s
83 %
0.77 s
2.09 s
1.94 s
Figure 7: Average of execution time of one instant for a 500x500 Fredkin’s cellular automata.
written in C.
The main application written in ReactiveML is a simulator of a complex network routing protocol for mobile ad-hoc
networks [3, 19], done in collaboration with F. Benbadis
(from the Network team at LIP6, Paris). Mobile ad-hoc
networks are highly dynamic networks characterized by the
absence of physical infrastructure. In such networks, every
node is able to move, nodes evolve concurrently and synchronize continuously with their neighbors. Due to mobility, connections in the network can change dynamically and nodes
can be added or removed at any time. All these characteristics — concurrency with many communications and the
need of complex data-structure — combined to the routing
protocol specifications make the use of standard simulation
tools (e.g., NS, OPNET) inadequate and network protocols
appear to be very hard to program efficiently in conventional
programming languages. This experiment showed that the
reactive model as introduced by Boussinot strongly matters
for programming those systems. It provides adequate programming constructs — namely synchronous parallel composition, broadcast communication and dynamic creation
— which allow for a natural implementation of the hard
part of the simulation. The complete ReactiveML implementation (with graphical interface, statistics) is about 1000
lines. Experimental results show that the ReactiveML implementation is two order of magnitude faster than the original C version; it was able to simulate more that 1000 nodes
where the original C version failed (after 200 nodes) and is
twice faster that the ad-hoc version directly programmed in
NAB [23]. A project is under way for using ReactiveML
for simulating network sensors, taking into account the temporal aspects of nodes (e.g., energy consumption or failure)
and to connect ReactiveML with automatic test sequences
generators such as Lurette [16].
8.
CONCLUSION AND RELATED WORKS
In this paper, we have presented an extension of an existing strict ML language with reactive constructs. The result
language is dedicated to the implementation of complex dynamic systems as found in graphical interfaces, video games
and simulation problems.
Compared to existing embedding of the reactive approach
in either an imperative language [8] or an object-oriented
language [1], the present work provides a complete semantics
of the embedding. This allows a precise understanding of
the communication between the two levels and reveals, in
particular, classical problems appearing in process calculi
such as scope-extrusion phenomena.
The Fair Threads [9, 27] are an extension of the reactive approach that allows to mix cooperative and preemptive
scheduling. In this model several synchronous schedulers
can be executed in an asynchronous way. The threads can
move from a scheduler to an other dynamically or can be
executed asynchronously out of all schedulers. The threads
that can be executed alone must be implemented over the
system threads, it limits the number of such threads and
it leads to efficiency problems. Contrary to ReactiveML,
in the Fair Threads, there is only top-level concurrency:
we cannot write (e1 ||e2 );e3 , and there is no hierarchical
control structures.
ULM [6] is a language dedicated to mobility. It also borrows the principles of synchronous reactive programming introduced by Boussinot and embed it inside a call-by-value
λ-calculus. In ULM, references are encoded like signals: accessing a reference which is not local is delayed until it becomes present. We did not address mobility issues and thus,
accessing a reference is instantaneous. In ReactiveML,
synchronization can only be done through the use of a signal and reactive construct must appear in particular places
of the program. In comparison, ULM allows to insert reactive constructs (e.g., pause) anywhere in an expression. As
a consequence, some overhead is imposed on the execution
on regular ML expressions. Indeed, reactive code is transformed into continuation-passing style by CPS transformation, whereas Ocaml code does not have to be modified.
We know that ML code cannot be interrupted, so we do not
have to introduce some mechanism to save the execution
context.
ConcurrentML [26] is a language that support concurrent programming and functional programming. As opposed
to ReactiveML, it is based on a preemptive scheduling.
The communication between processes is made by communication channels or shared memory. To control concurrent access to the memory, ConcurrentML uses semaphores, mutex locks and condition variables, whereas in ReactiveML
we do not have to use them because we have the guaranty
by the compilation of the concurrency that instantaneous
actions are atomic. In ReactiveML, there is a sequential
run-time (there is no concurrency during the execution).
The language is very young and several extensions can be
considered. In particular, an important work must be done
concerning the efficiency of the execution in order to use
ReactiveML for programming real-size simulation problems and to be a convincing alternative to traditional methods. For example, the recognition of subparts of a reactive
program which can be compiled (that is, statically scheduled) is still open. Whereas causality inconsistencies are
eliminated in the Boussinot model, the scope extrusion phenomena (which is absent in existing synchronous languages)
make this compilation difficult and calls for new program
analysis.
9. REFERENCES
[1] R. Acosta-Bermejo. Rejo Langage d’Objets Réactifs et
d’Agents. PhD thesis, Ecole des Mines de Paris, 2003.
[2] Raul Acosta-Bermejo. Reactive operating system,
reactive java objects. In NOTERE’2000, Paris,
November 2000. ENST.
[3] F. Benbadis, M. Dias de Amorim, and S. Fdida. ELIP:
Embedded location information protocol. In IFIP
Networking 2005 Conference, 2005.
[4] A. Benveniste, P. Caspi, S. Edwards, N. Halbwachs,
P. Le Guernic, and R. de Simone. The Synchronous
Languages Twelve Years Later. Proceedings of the
IEEE, 2003.
[5] G. Berry. The constructive semantics of esterel, 1998.
[6] Gérard Boudol. ULM a core programming model for
global computing. In Proceedings of the European
Symposium on Programming, 2004.
[7] Frédéric Boussinot. Reactive C: An extension of C to
program reactive systems. Software Practice and
Experience, 21(4):401–428, Apr 1991.
[8] Frédéric Boussinot. Concurrent programming with
Fair Threads: The LOFT language, 2003.
[9] Frédéric Boussinot. FairThreads: mixing cooperative
and preemptive threads in C. Research report 5039,
INRIA, 2003.
[10] Frédéric Boussinot. Reactive programming of cellular
automata. Technical Report 5183, INRIA, 2004.
[11] Frédéric Boussinot and Robert de Simone. The SL
synchronous language. Software Engineering,
22(4):256–266, 1996.
[12] Frédéric Boussinot, Jean-Ferdinand Susini,
Frédéric Dang Tran, and Laurent Hazard. A reactive
behavior framework for dynamic virtual worlds. In
Proceedings of the sixth international conference on
3D Web technology, pages 69–75. ACM Press, 2001.
[13] Frédéric Boussinot and Jean-Ferdinant Susini. The
sugarcubes tool box - a reactive java framework.
Software Practice and Experience, 28(14):1531–1550,
1998.
[14] N. Halbwachs, P. Raymond, and C. Ratel. Generating
efficient code from data-flow programs. In Third
International Symposium on Programming Language
Implementation and Logic Programming, Passau
(Germany), August 1991.
[15] Laurent Hazard, Jean-Ferdy Susini, and Frédéric
Boussinot. The Junior reactive kernel. Research report
3732, INRIA, 1999.
[16] E. Jahier, P. Raymond, and P. Baufreton. Case
studies with Lurette V2. In Proceedings of the First
International Symposium on Leveraging Applications
of Formal Method, 2004.
[17] G. Kahn. The semantics of a simple language for
parallel programming. In IFIP 74 Congress. North
Holland, Amsterdam, 1974.
[18] Xavier Leroy. The Objective Caml system release
3.08. Documentation and user’s manual. Technical
report, INRIA, 2004.
[19] Louis Mandel and Farid Benbadis. Simulation of
mobile ad hoc network protocols in ReactiveML.
Submitted to publication.
[20] Louis Mandel and Marc Pouzet. ReactiveML, a
reactive extension to ML (extended version).
Submitted to PPDP’05.
[21] R. Milner. A theory of type polymorphism in
programming. Journal of Computer and System
Science, 17:348–375, 1978.
[22] Robin Milner. Communicating and Mobile Systems:
The π-Calculus. Cambridge University Press, 1999.
[23] Network in A Box. http://nab.epfl.ch/.
[24] Benjamin C. Pierce. Basic Category Theory for
Computer Scientists. MIT Press, 1991.
[25] Riccardo Pucella. Reactive programming in Standard
ML. In Proceedings of the IEEE International
Conference on Computer Languages, pages 48–57.
IEEE Computer Society Press, 1998.
[26] John H. Reppy. Concurrent Programming in ML.
Cambridge University Press, 1999.
[27] Manuel Serrano, Frédéric Boussinot, and Bernard
Serpette. Scheme fair threads. In Proceedings of the
6th ACM SIGPLAN international conference on
Principles and practice of declarative programming,
pages 203–214. ACM Press, 2004.
APPENDIX
A. PROOFS
So we have
E3 , b3
E3 , b3
2
2
e023
−−→
N32 ` e2 −−−
1
1
−−→
e013
N31 ` e1 −−−
S3
S3
A.1 Proof of lemma 1
E31 tE32 , b31 ∧b32
N31 · N32 ` e1 ||e2 −−−−−−−−−−−−→ e013 ||e023
S3
We first start with an auxiliary property. The semantics
of ML is deterministic.
Lemma 8. For every expression e, if e ⇓ v1 and e ⇓ v2
then v1 = v2 .
The proof of (b31 ∧b32 ) ⇒ ((b11 ∧b12 )∧(b21 ∧b22 )) is made
from the hypothesis b31 ⇒ b11 ∧ b21 and b32 ⇒ b12 ∧ b22 .
Now we prove the determinism of the behavioral semantics
by structural induction on the derivations. We just present
the most interesting case.
We can prove easily that N31 ∪N32 ⊆ (N11 ∪N12 )∩(N21 ∪
N2 2 )
Case let e(x) in e0 : There is only one rule that can be
applied.
E31 t E32 v (E11 t E12 ) u (E21 t E22 )
e ⇓ n1
S(n1 ) = (d1 , g1 , m1 )
v1 = fold g1 m1 d1
The last point that we have to prove is:
From the hypothesis E31 v (E11 u E21 ) and E32 v (E12 u
E22 ) we have
∅, false
N ` let e(x) in e0 −−−−→ e0 [x ← v1 ]
S
e ⇓ n2
S(n2 ) = (d2 , g2 , m2 )
v2 = fold g2 m2 d2
∅, false
N ` let e(x) in e0 −−−−→ e0 [x ← v2 ]
E 31
v E 11
(1)
E 31
E 32
E 32
v E 21
v E 12
v E 22
(2)
(3)
(4)
The union of (1) and (3) and the union of (2) and (4) give
S
with lemma 8, n1 = n2 so S(n1 ) = S(n2 ) = (d, g, v). With
the property of associativity and commutativity of the gathering functions, we are sure that fold is deterministic, thus
v1 = v2 . Hence e0 [x ← v1 ] = e0 [x ← v2 ].
E 31 t E 32
v E 11 t E 12
(5)
E 31 t E 32
v E 21 t E 22
(6)
the intersection of (5) and (6) is
(E31 t E32 ) u (E31 t E32 ) v (E11 t E12 ) u (E21 t E22 )
A.2 Proof of lemma 3
By structural induction on the derivations. We just present
two typical cases: the parallel composition and the present.
which is equal to
Case e1 ||e2 : For the parallel composition there is only
one rule that can be applied:
Case present e then e1 else e2 : With the determinism
of ML (lemma 8), we have that e ⇓ n.
E1 , b1
1
1
−−→
e011
N11 ` e1 −−−
S1
E31 t E32 v (E11 t E12 ) u (E21 t E22 )
• Case n 6∈ S3 : In this case the expression can react
E1 , b 1
2
2
−−→
e021
N12 ` e2 −−−
e⇓n
S1
E1 tE1 , b1 ∧b1
2
1
e011 ||e021
−−−2−−−1−−−→
N11 · N12 ` e1 ||e2 −−−
n 6∈ S3
∅, false
∅ ` present e then e1 else e2 −−−−→ e2
S3
S1
E 21 , b 21
N21 ` e1 −−−−−→
S2
e012
E 22 , b 22
N22 ` e2 −−−−−→
S2
e022
E21 tE22 , b21 ∧b22
N21 · N22 ` e1 ||e2 −−−−−−−−−−−−→ e012 ||e022
S2
and this is trivial to check the properties false ⇒ b1 ∧b2 ,
∅ v E1 u E2 and ∅ ⊆ N1 ∩ N2 .
• Case n ∈ S3 : By hypothesis n ∈ S3 ⇒ (n ∈ S1 ∧ n ∈
S2 ). So
e⇓n
By the induction hypothesis,
n ∈ S1
E ,b
1
e011
N1 ` e1 −−1−−→
S1
E ,b
E3 , b3
1
1
e013
−−→
N31 ` e1 −−−
S3
E3 , b3
2
2
e023
−−→
N32 ` e2 −−−
1
e011
N1 ` present e then e1 else e2 −−1−−→
S1
S3
and b31 ⇒ b11 ∧ b21 and b32 ⇒ b12 ∧ b22 and E31 v E11 u E21
and E32 v E12 u E22 and N31 ⊆ N11 ∩ N21 and N32 ⊆
N1 2 ∩ N 2 2 .
To apply the rule of the parallel in the environment S3 ,
we first have to prove that N31 ∩ N32 ⊆ ∅.
From the hypothesis, we have N31 ∩ N32 ⊆ (N11 ∩ N21 ) ∩
(N12 ∩ N22 ). By associativity and commutativity N31 ∩
N32 ⊆ (N11 ∩ N12 ) ∩ (N22 ∩ N22 ). With the definition of
“·”, we have N11 ∩ N12 = ∅ and N22 ∩ N22 = ∅. Hence
N31 ∩ N32 ⊆ ∅.
e⇓n
n ∈ S2
E ,b
2
e012
N2 ` e1 −−2−−→
S2
E ,b
2
e012
N2 ` present e then e1 else e2 −−2−−→
S2
By induction and with the rule of present
e⇓n
n ∈ S3
E ,b
3
e013
N3 ` e1 −−3−−→
S3
E ,b
3
e013
N3 ` present e then e1 else e2 −−3−−→
S3
and b3 ⇒ b1 ∧ b2 and E3 v E1 u E2 and N3 ⊆ (N1 ∩ N2 ).