The language is a functional language: functions are first-class
objects which can be given to functions or returned by functions. For
example, the `it`

function feeds back a network (i.e, it iterates
a function on a stream of values). It graphical representation is
given in figure 1.6.

let node it f init x = y where rec y = f x (init fby y) val it : (’a -> ’b -> ’b) -> ’b -> ’a => ’b val it :: (’a -> ’b -> ’b) -> ’b -> ’a -> ’b

such that:

sum x = it (+) 0 x

Note that type signature of `it`

states that its argument
`f`

is considered to be a combinatorial function. To make a (more
general) rewinding operator for a stateful function, one has to write
instead:

let node it f init x = y where rec y = run (f x) (init fby y) val it : (’a -> ’b => ’b) -> ’b -> ’a => ’b val it :: (’a -> ’b -> ’b) -> ’b -> ’a -> ’b

The `run`

keyword used in an expression states that its argument
is expected to be a stateful function. Thus, `run (f x)`

indicates that `f x`

must have some type *t*_{1} ⇒ *t*_{2}
instead of *t*_{1} → *t*_{2}.

Higher-order is a natural way to build new primitives from existing
ones. For example, the so-called “activation condition” is a
build-in operator in block-diagram design tools (*à la*
Scade/Lustre or Simulink). An activation condition takes a function
`f`

, a clock `clk`

, a `default`

value and an
`input`

an computes `f(input when clk)`

. It then sets the
result on the base clock.

let node cond_act f clk default input = let rec o = merge clk (run f (input when clk)) ((default fby o) whenot clk) in o node cond_act : (’a => ’b) -> bool -> ’b -> ’a -> ’b node cond_act :: (’a on _c0 -> ’a on _c0) -> (_c0:’a) -> ’a -> ’a -> ’a

Using the `cond_act`

construction, one can rewrite the
`RisingEdgeRetrigger`

operator given in
section 1.2.2 as the following:

let node count_down (res, n) = cpt where rec cpt = if res then n else (n -> pre (cpt - 1)) let node rising_edge_retrigger rer_input number_of_cycle = rer_output where rec rer_output = (0 < v) & clk and v = cond_act count_down clk 0 (count, number_of_cycle) and c = false fby rer_output and clock clk = c or count and count = false -> (rer_input & pre (not rer_input))

The symmetric operation of the activation condition is an *iterator* which simulates an internal `for`

or `while`

loop, generalizing what has been done in paragraph 1.2.3.
This operator consists in iterating a function on an input.

let node iter clk init f input = (* read input when clk is true *) let rec i = merge clk input ((init fby i) whenot clk) in let rec o = f i po and po = merge clk (init when clk) ((init fby o) whenot clk) in (* emit output when clk is true *) o when clk val iter : clock -> ’a -> (’a -> ’a -> ’a) -> ’a => ’a val iter :: (_c0:’a) -> ’a -> (’a -> ’a -> ’a) -> ’a on _c0 -> ’a on _c0

`iter clk init f input`

reads an `input`

every time
`clk`

is true and computes `f`

. The computation takes place
at every instant (on clock `'a`

) whereas `input`

is read
only when `clk`

is true.

We can illustrate this operator on the computation of the power of a
sequence. Let `x`

be some stream with clock `'a on clk`

such
that the number of instants between two successive true values of
`clk`

is *k*. Now, write a program which computes the sequence
(*y*_{i})_{i ∈ IN} such that *y*_{0} = 1 and *y*_{i+1} =
*x*_{i}^{ki}.

clk | t | f | f | t | f | t | f | f | f | t | t | ... |

x | x_{0} | x_{1} | x_{2} | x_{3} | x_{4} | ... | ||||||

k | 1 | 2 | 3 | 1 | 2 | 1 | 2 | 3 | 4 | 1 | 1 | ... |

y | 1 | x_{0}^{3} | x_{1}^{2} | x_{2}^{4} | x_{3} | ... |

This program can be implemented in the following way:

let node power clk x = o where o = iter clk 1 (fun i acc -> i * acc) x let node power10 x = power ten x

Here are some typical combinators.

let node (||) f g x = (run f x, run g x) let node (>) f g x = run g (run f x) let clock half = h where rec h = true -> not (pre h) let node alternate f g x = merge half (run f (x when half)) (run g (x whenot half)) val || : (’a => ’b) -> (’a => ’c) -> ’a => ’b * ’c val || :: (’a -> ’b) -> (’a -> ’c) -> ’a -> ’b * ’c val > : (’a => ’b) -> (’b => ’c) -> ’a => ’c val > :: (’a -> ’b) -> (’b -> ’c) -> ’a -> ’c val half : bool val half :: ’a val alternate : (’a => ’b) -> (’a => ’b) -> ’a => ’b val alternate :: (’a on half -> ’b on half) -> (’a on not half -> ’b on not half) -> ’a -> ’b

The infix operator `(||)`

computes the product of two functions
`f`

and `g`

and `(>)`

composes two
functions. `alternate`

alternates the execution of a function
with another one.

All the programs defined above still define reactive systems: programs are compiled into finite state machines answering in bounding time and space whatever be their input.

In the examples considered previously, function used as parameters do
not evolve during the execution. Intuitively, the `it`

function
receives a stream function `f`

and instantiates it once.

The language provides some means to deal with streams of
functions. This is strictly more expressive that the previous case and
is a way to model *reconfigurable* systems.

The function application instantiates a function with some
argument. We can define a more general operator, say
`reconfigure`

which expects a stream of function `code`

, an
argument and instantiates the current value of the code every time a
new code is received.

let node reconfigure code input = o where rec automaton Await -> do unless code(c) then Run(c) | Run(c) -> do emit o = c input unless code(c) then Run(c) end

We can make the example a little more complicated by bounding the time
for computing `c input`

. For example:

let node server code input money = o where automaton Await -> do unless code(c) & money(m) then Run(c,m) | Run(c,m) -> let rec cpt = m -> pre cpt - 1 in do emit o = c input until (cpt = 0) then Await end