The language provides a way to manage valued signals. Signals
are built and accessed through the construction
present. A value signal is a pair made of (1) a boolean stream
c indicating when the signal is present and (2) a stream sampled on
that clock c 6. In circuit
terminology, we get circuits with enable.
Signals can be built from sampled streams by abstracting their internal clock. Consider again the example given in section 1.2.5. This program can now be accepted if we write:
let node within min max x = o where rec clock c = (min <= x) & (x <= max) and emit o = true when c val within : ’a -> ’a -> ’a => bool sig val within :: ’a -> ’a -> ’a -> ’a sig
It computes a condition
c and a sampled stream
true when c. The equation emit o = true when c defines
o which is present and equal to
c is true. The
emit construction can be considered as a
boxing mechanism which pack a value with its clock condition. The
right part of the construction
emit must be an expression with
some clock type a on c. In that case, it defines a signal
with clock type a sig.
It is possible to test for the presence of a signal expression e by
writting the boolean expression ? e. The following program, for
example, counts the number of instants where
x is emitted.
let node count x = cpt where rec cpt = if ?x then 1 -> pre cpt + 1 else 0 -> pre cpt val count : ’a sig => int val count :: ’a sig -> ’a
The language provides a more general mechanism to test for the presence of several signals and access their values. It is reminiscent of the pattern-matching construct of ML. This pattern matching mechanisn is safe in the sense that it is possible to access the value of a signal only at the instant where it is emitted. This is in contrast with Esterel, for example, where the value of a signal implicitly holds and can be accessed even when it is not emitted.
The following program takes two signals
returns an integer which equals the sum of
both are emitted, it returns the value of
emitted only and the value
0 when only
y is emitted and
let node sum x y = o where present x(v) & y(w) -> do o = v + w done | x(v1) -> do o = v1 done | y(v2) -> do o = v2 done | _ -> do o = 0 done end val sum : int sig -> int sig => int val sum :: ’a sig -> ’a sig -> ’a
present statement is made of several signal conditions and
handlers. Each condition is tested sequentially. The signal condition
x(v) & y(w) is verified when both signals
are present. A condition
x(v1) means “
x is present and
has some value
v1”. The variable
v1 can in turn be used
in the corresponding handler. The last signal condition
stands for the wildcard signal condition which is always verified.
In the signal pattern
x(v) & y(w),
expressions evaluating to signal values whereas
stand for patterns. Thus, writting
x(42) & y(w) would mean:
“await for the presence of signal
x evaluating to
and the presence of
Note that the output of the function
sum is a regular flow
since the test is exhaustive. Forgetting the default case will raise
let node sum x y = o where present x(v) & y(w) -> do o = v + w done | x(v1) -> do o = v1 done | y _ -> do o = 0 done end File "test.ls", line 6-10, characters 2-105: >..present > x(v) & y(w) -> do o = v + w done > | x(v1) -> do o = v1 done > | y _ -> do o = 0 done > end The identifier o should be defined in every handler or given a last value.
We can easily eliminate this error by giving a last value to
(e.g., adding an equation
last o = 0 outside of the present
statement). In that case, the default case is implicitly completed
with an equation
o = last o. The other way is to state that
o is now a signal and is thus only partially defined.
let node sum x y = o where present x(v) & y(w) -> do emit o = v + w done | x(v1) -> do emit o = v1 done | y _ -> do emit o = 0 done end val sum : int sig -> int sig => int sig val sum :: ’a sig -> ’a sig -> ’a sig
A signal pattern may also contain boolean expressions. The following
program, sums the values of the two signals
provided they arrive at the same time and
z >= 0.
let node sum x y z = o where present x(v) & y(w) & (z >= 0) -> do o = v + w done | _ -> do o = 0 done end
Remark: Using signals, we can mimic the
default construction of the language
default x y emits the value of
is present and the value of
x is absent and
y is present.
let node default x y = o where present x(v) -> do emit o = v done | y(v) -> do emit o = v done end
This is, of course, only a simulation since all the information about
clocks has been lost. In particular, the compiler is unable to state
o is emitted only when
y are present as
the clock calculus of Signal does for the default operator.
In some circumstances, it can be valuable to prefer sampling operators
merge in order to benefit from clock