ReactiveML Manual


ReactiveML is based on the synchronous reactive model embedded in an ML language (here a subset of OCaml). It provides synchronous parallel composition and dynamic features like the dynamic creation of processes. In ReactiveML, the reactive model is integrated at the language level (not as a library) which leads to safer and more natural programming.

Compiling ReactiveML Programs

Let hello.rml be a file containing the following program:

  let process main = print_endline "Hello World!"

To produce an executable, first the file must be compiled into pure OCaml code using the following command (the -s option allows to define the main process):

  rmlc -s main hello.rml

Then, the generated OCaml file (hello.ml) can compiled and linked with the ReactiveML runtime as follows:

  ocamlopt -o hello -I `rmlc -where` unix.cmxa rmllib.cmxa hello.ml

It produces an executable file hello which displays Hello World!.

You can also automate the compilation of ReactiveML programs using rmlbuild. To do that, first define a file hello.rmlsim which containts the main process:

  sim: main

Then you can compile the ReactiveML file and the generated OCaml file in one command:

  rmlbuild hello.rml.native

This tool is based on ocamlbuild.


Summary of ReactiveML Expressions

Terminal symbols are set in typewriter font. Non-terminal symbols are set in italic font. Square brackets [] denote optional components. Curly brackets {} denote zero, one or several repetitions of the enclosed components. Parentheses () denote grouping and | denotes alternatives.


Process Definition

  let process <id> { <pattern> } = <expr> in <expr>
  process <expr>

Process definition are introduced by the process keyword.
A process can be named (let process id ... ) or anonymous (process <expr>).


Basic statements

  nothing
  pause
  halt
  run <process>

nothing is equivalent to().
pause suspends the execution until next instant.
halt suspends the execution forever.
run executes a process.


Composition

  <expr> ; <expr>
  <expr> || <expr>
  let <pattern> = <expr> { and <pattern> = <expr> } in <expr>
  <expr> |> <expr>

In ReactiveML, expressions can be composed in sequence (;) or in parallel (||). The let/and/in construct computes several expressions in parallel and gets their values, then it computes the right of the in.

The expression e1 |> e2 executes e1 and e2 in parallel, but at each instant e1 is executed before e1 (this construct is not supported in all runtime).


Iterators

  loop <expr> end
  while <expr> do <expr> done
  for <id> = <expr> ( to  |  downto )  do <expr> done
  for <id> = <expr> ( to  |  downto ) dopar <expr> done

loop is an infinite loop. while and for/do are the classical loops. They execute their body several times in sequence. Contrarily, the for/dopar loop executes its body several times in parallel.


Signal declaration

  signal <id> { , <id> } in  <expr>
  signal <id> default <value> gather <function> in  <expr>

These constructs declare new signals. When a signal is declared, we can define how to combine the values emitted during an instant with the signal/gather construct. If no combination function is given, the behavior of the signal is to collect all emitted values in a list.


Signal emission

  emit <signal> [ <value> ]

Signal emissions are instantaneous broadcasting. Hence, a signal is present or absent during an instant but it cannot have both status. The notation emit <signal> is a shortcut for emit <signal> ().


Signal status

  present <signal> then <expr> else <expr>
  await [ immediate ] <signal>
  pre <signal>

The expression present tests the status of a signal. If the signal is present, the then branch is executed instantaneously, otherwise the else branch is executed at the following instant.

The expression await s waits s to be emitted and terminates at the following instant. Whereas the expression await immediate s waits s to be emitted and terminates instantaneously.

Like in Esterel, the non-immediate version of await is the default one such that await s; await s waits two occurrences of s, while await immediate s; await immediate s is equivalent to await immediate s.

The expression pre s evaluates to true if the signal s has been emitted at the preceding instant. Otherwise, it evaluates to false.


Signal value

  await <signal> (<pattern>) [ when <expr> ] in <expr>
  await [ immediate ] one <signal> (<variable>) in <expr>
  pre ?<signal>
  last ?<signal>
  default ?<signal>

The await/in waits the emission of a signal. At the instant following the emission, the body is executed in an environment where the pattern is bind to the value of the signal (the combination of the values emitted at the preceding instant). Notice that the await/in keeps waiting when the value of the signal does not match the pattern or if the condition specified after the when keyword is not satisfied.

The await/one/in construct waits the emission of a signal to bind the pattern with one of the emitted values. In case of multiple emission during an instant, the choice of the value is not specified. Like await, the body of the expression is executed at the instant following the reception of the signal (except if there is the immediate keyword). To be causal by construction, there is no immediate version of the await/in construct.

The expression pre ?s evaluates to the value associated to s at the preceding instant. If s has not been emitted at the preceding instant, pre ?s is equal to the default value given at the declaration point of the signal. last ?s has a slight different behavior. It evaluates to the last value associated to s when it was emitted. While s has never been emitted, pre ?s and last ?s both evaluates to the default value of s.

The default function returns the default value of a signal.


Control structures

  do <expr> when <signal> done
  control <expr> with <signal> [ (<pattern>) [ when  <expr> ] done
  do <expr> until <signal> [ (<pattern>) [ when  <expr> ] [ ->  <expr> ] ] done

do/when and control/with allows to suspend the execution of and expression. The do/when executes its body only when the signal is present. The control/with switches between an active mode and a suspended one each time that the signal is present.

The preemption construct do/until stops the execution of its body at the end of instant when the signal is emitted. The second do/until executes a handler when a preemption occurs.