more updates
[phd-thesis.git] / top / lang.tex
1 \documentclass[../thesis.tex]{subfiles}
2
3 \input{subfilepreamble}
4
5 \begin{document}
6 \input{subfileprefix}
7 \chapter{The \texorpdfstring{\gls{MTASK}}{mTask} language}%\texorpdfstring{\glsxtrshort{DSL}}{DSL}}%
8 \label{chp:mtask_dsl}
9 \begin{chapterabstract}
10 \noindent This chapter introduces the \gls{TOP} language \gls{MTASK} language by:
11 \begin{itemize}
12 \item introducing the setup of the \gls{EDSL};
13 \item and showing the language interface and examples for the type system, data types, expressions, tasks and their combinators.
14 \end{itemize}
15 \end{chapterabstract}
16
17 The \gls{MTASK} system is a complete \gls{TOP} programming environment for programming microcontrollers.
18 This means that it not only contains a \gls{TOP} language but also a \gls{TOP} engine.
19 It is implemented as an \gls{EDSL} in \gls{CLEAN} using class-based---or tagless-final---embedding (see \cref{sec:tagless-final_embedding}).
20 Due to the nature of the embedding technique, it is possible to have multiple interpretations for programs written in the \gls{MTASK} language.
21 Not all of these intepretations are necessarily \gls{TOP} engines, some may perform an analysis over the program or typeset the program so that the output can be shown after evaluating the expression at run time.
22 The following interpretations are available for \gls{MTASK}.
23
24 \begin{description}
25 \item[Printer]
26
27 This interpretation converts the expression to a string representation.
28 As the host language \gls{CLEAN} constructs the \gls{MTASK} expressions at run time, it can be useful to show the constructed expression.
29 \item[Simulator]
30
31 The simulator converts the expression to a ready-for-work \gls{ITASK} simulation in which the user can inspect and control the simulated peripherals and see the internal state of the tasks.
32 \item[Byte code compiler]
33
34 The compiler compiles the \gls{MTASK} program to a specialised byte code.
35 Using a handful of integration functions and tasks (see \cref{chp:integration_with_itask}), \gls{MTASK} tasks can be executed on microcontrollers and integrated in \gls{ITASK} as if they were regular \gls{ITASK} tasks.
36 Furthermore, with special language constructs, \glspl{SDS} can be shared between \gls{MTASK} and \gls{ITASK} programs.
37 \end{description}
38
39 When using the byte code compiler interpretation in conjunction with the \gls{ITASK} integration, \gls{MTASK} is a heterogeneous \gls{DSL}.
40 I.e.\ some components---e.g.\ the \gls{RTS} on the microcontroller---is largely unaware of the other components in the system, and it is executed on a completely different architecture.
41 The \gls{MTASK} language is an enriched simply-typed $\lambda$-calculus with support for some basic types, arithmetic operations, and function definition; and a task language (see \cref{sec:top}).
42
43 \section{Types}
44 To leverage the type checker of the host language, types in the \gls{MTASK} language are expressed as types in the host language, to make the language type safe.
45 However, not all types in the host language are suitable for microcontrollers that may only have \qty{2}{\kibi\byte} of \gls{RAM} so class constraints are therefore added to the \gls{DSL} functions.
46 The most used class constraint is the \cleaninline{type} class collection containing functions for serialization, printing, \gls{ITASK} constraints, \etc.
47 Many of these functions can be derived using generic programming.
48 An even stronger restriction on types is defined for types that have a stack representation.
49 This \cleaninline{basicType} class has instances for many \gls{CLEAN} basic types such as \cleaninline{Int}, \cleaninline{Real} and \cleaninline{Bool}.
50 The class constraints for values in \gls{MTASK} are omnipresent in all functions and therefore often omitted throughout throughout the chapters for brevity and clarity.
51
52 \begin{table}[ht]
53 \centering
54 \caption{Translation from \gls{CLEAN}\slash\gls{MTASK} data types to \ccpp{} datatypes.}%
55 \label{tbl:mtask-c-datatypes}
56 \begin{tabular}{lll}
57 \toprule
58 \gls{CLEAN}\slash\gls{MTASK} & \ccpp{} type & \textnumero{}bits\\
59 \midrule
60 \cleaninline{Bool} & \cinline{bool} & 16\\
61 \cleaninline{Char} & \cinline{char} & 16\\
62 \cleaninline{Int} & \cinline{int16_t} & 16\\
63 \cleaninline{Real} & \cinline{float} & 32\\
64 \cleaninline{:: Long} & \cinline{int32_t} & 32\\
65 \cleaninline{:: T = A \| B \| C} & \cinline{enum} & 16\\
66 \bottomrule
67 \end{tabular}
68 \end{table}
69
70 \Cref{lst:constraints} contains the definitions for the auxiliary types and type constraints (such as \cleaninline{type} and \cleaninline{basicType}) that are used to construct \gls{MTASK} expressions.
71 The \gls{MTASK} language interface consists of a core collection of type classes bundled in the type class \cleaninline{class mtask}.
72 Every interpretation implements the type classes in the \cleaninline{mtask} class
73 There are also \gls{MTASK} extensions that not every interpretation implements such as peripherals and \gls{ITASK} integration.
74 \begin{lstClean}[caption={Classes and class collections for the \gls{MTASK} language.},label={lst:constraints}]
75 class type t | iTask, ... ,fromByteCode, toByteCode t
76 class basicType t | type t where ...
77
78 class mtask v | expr, ..., int, real, long v
79 \end{lstClean}
80
81 Sensors, \glspl{SDS}, functions, \etc{} may only be defined at the top level.
82 The \cleaninline{Main} type is used that is used to distinguish the top level from the main expression.
83 Some top level definitions, such as functions, are defined using \gls{HOAS}.
84 To make their syntax friendlier, the \cleaninline{In} type---an infix tuple---is used to combine these top level definitions as can be seen in \cleaninline{someTask} (\cref{lst:mtask_types}).
85
86 \begin{lstClean}[caption={Example task and auxiliary types in the \gls{MTASK} language.},label={lst:mtask_types}]
87 :: Main a = { main :: a }
88 :: In a b = (In) infix 0 a b
89
90 someTask :: MTask v Int | mtask v & liftsds v & sensor1 v & ...
91 someTask =
92 sensor1 config1 \sns1->
93 sensor2 config2 \sns2->
94 sds \s1 = initialValue
95 In liftsds \s2 = someiTaskSDS
96 In fun \fun1= ( ... )
97 In fun \fun2= ( ... )
98 In { main = mainexpr }
99 \end{lstClean}
100
101 \Gls{MTASK} expressions are usually overloaded in their interpretation (\cleaninline{v}).
102 In \gls{CLEAN}, all free variables in a type are implicitly universally quantified.
103 In order to use the \gls{MTASK} expressions with multiple interpretations, rank-2 polymorphism is required \citep{odersky_putting_1996}\citep[\citesection{3.7.4}]{plasmeijer_clean_2021}.
104 \Cref{lst:rank2_mtask} shows an example of a function that simulates an \gls{MTASK} expression while showing the pretty printed representation in parallel.
105 Providing a type for the \cleaninline{simulateAndPrint} function is mandatory as the compiler cannot infer the type of rank-2 polymorphic functions.
106
107 \begin{lstClean}[label={lst:rank2_mtask},caption={Rank-2 polymorphism to allow multiple interpretations}]
108 prettyPrint :: Main (MTask PrettyPrint a) -> String
109 simulate :: Main (MTask Simulate a) -> Task a
110
111 simulateAndPrint :: (A.v: Main (MTask v a) | mtask v) -> Task a | type a
112 simulateAndPrint mt =
113 simulate mt
114 -|| Hint "Current task:" @>> viewInformation [] (prettyPrint mt)
115 \end{lstClean}
116
117 \section{Expressions}\label{sec:expressions}
118 This section shows all \gls{MTASK} constructs for exppressions.
119 \Cref{lst:expressions} shows the \cleaninline{expr} class containing the functionality to lift values from the host language to the \gls{MTASK} language (\cleaninline{lit}); perform number and boolean arithmetics; do comparisons; and conditional execution.
120 For every common boolean and arithmetic operator in the host language, an \gls{MTASK} variant is present, suffixed by a period to not clash with \gls{CLEAN}'s builtin operators.
121
122 \begin{lstClean}[caption={The \gls{MTASK} class for expressions},label={lst:expressions}]
123 class expr v where
124 lit :: t -> v t | type t
125 (+.) infixl 6 :: (v t) (v t) -> v t | basicType, +, zero t
126 ...
127 (&.) infixr 3 :: (v Bool) (v Bool) -> v Bool
128 (|.) infixr 2 :: (v Bool) (v Bool) -> v Bool
129 Not :: (v Bool) -> v Bool
130 (==.) infix 4 :: (v a) (v a) -> v Bool | Eq, basicType a
131 ...
132 If :: (v Bool) (v t) (v t) -> v t | type t
133 \end{lstClean}
134
135 Conversion to-and-fro data types is available through the overloaded functions \cleaninline{int}, \cleaninline{long} and \cleaninline{real} that will convert the argument to the respective type similar to casting in \gls{C}.
136 For most interpretations, there are instances of these classes for all numeric types.
137
138 \begin{lstClean}[caption={Type conversion functions in \gls{MTASK}.}]
139 class int v a :: (v a) -> v Int
140 class real v a :: (v a) -> v Real
141 class long v a :: (v a) -> v Long
142 \end{lstClean}
143
144 Values from the host language must be explicitly lifted to the \gls{MTASK} language using the \cleaninline{lit} function.
145 For convenience, there are many lower-cased macro definitions for often used constants such as \cleaninline{true :== lit True}, \cleaninline{false :== lit False}, \etc.
146
147 \Cref{lst:example_exprs} shows some examples of these expressions.
148 Since they are only expressions, there is no need for a \cleaninline{Main}.
149 \cleaninline{e0} defines the literal $42$, \cleaninline{e1} calculates the literal $42.0$ using real numbers.
150 \cleaninline{e2} compares \cleaninline{e0} and \cleaninline{e1} as integers and if they are equal it returns the \cleaninline{e2}$/2$ and \cleaninline{e0} otherwise.
151
152 \begin{lstClean}[label={lst:example_exprs},caption={Example \gls{MTASK} expressions.}]
153 e0 :: v Int | expr v
154 e0 = lit 42
155
156 e1 :: v Real | expr v
157 e1 = lit 38.0 + real (lit 4)
158
159 e2 :: v Int | expr v
160 e2 = if' (e0 ==. int e1)
161 (int e1 /. lit 2) e0
162 \end{lstClean}
163
164 \Gls{MTASK} is shallowly embedded in \gls{CLEAN} and the terms are constructed at runtime.
165 This means that \gls{MTASK} programs can also be tailor-made at runtime or constructed using \gls{CLEAN} functions maximising the linguistic reuse \citep{krishnamurthi_linguistic_2001}
166 \cleaninline{approxEqual} in \cref{lst:example_macro} performs a simple approximate equality---albeit without taking into account all floating point pecularities.
167 When calling \cleaninline{approxEqual} in an \gls{MTASK} function, the resulting code is inlined.
168
169 \begin{lstClean}[label={lst:example_macro},caption={Example linguistic reuse in the \gls{MTASK} language.}]
170 approxEqual :: (v Real) (v Real) (v Real) -> v Real | expr v
171 approxEqual x y eps = if' (x ==. y) true
172 ( if' (x >. y)
173 (y -. x < eps)
174 (x -. y < eps)
175 )
176 \end{lstClean}
177
178 \subsection{Data types}
179 Most of \gls{CLEAN}'s fixed-size basic types are mapped on \gls{MTASK} types.
180 However, it can be useful to have access to compound types as well.
181 All types in \gls{MTASK} must have a fixed size representation on the stack so sum types are not (yet) supported.
182 While it is possible to lift types using the \cleaninline{lit} function, you cannot do anything with the types besides passing them around but they are being produced by some parallel task combinators (see \cref{sssec:combinators_parallel}).
183 To be able to use types as first class citizens, constructors and field selectors are required (see \cref{chp:first-class_datatypes}).
184 \Cref{lst:tuple_exprs} shows the scaffolding for supporting tuples in \gls{MTASK}.
185 Besides the constructors and field selectors, there is also a helper function available that transforms a function from a tuple of \gls{MTASK} expressions to an \gls{MTASK} expression of a tuple.
186 Examples for using tuple can be found in \cref{sec:mtask_functions}.
187
188 \begin{lstClean}[label={lst:tuple_exprs},caption={Tuple constructor and field selectors in \gls{MTASK}.}]
189 class tupl v where
190 tupl :: (v a) (v b) -> v (a, b) | type a & type b
191 first :: (v (a, b)) -> v a | type a & type b
192 second :: (v (a, b)) -> v b | type a & type b
193
194 tupopen f :== \v->f (first v, second v)
195 \end{lstClean}
196
197 \subsection{Functions}\label{sec:mtask_functions}
198 Adding functions to the language is achieved by type class to the \gls{DSL}.
199 By using \gls{HOAS}, both the function definition and the calls to the function can be controlled by the \gls{DSL} \citep{pfenning_higher-order_1988,chlipala_parametric_2008}.
200 The \gls{MTASK} only allows first-order functions and does not allow partial function application.
201 This is restricted by using a multi-parameter type class where the first parameter represents the arguments and the second parameter the view.
202 By providing a single instance per function arity instead of providing one instance for all functions and using tuples for the arguments this constraint can be enforced.
203 Also, \gls{MTASK} only supports top-level functions which is enforced by the \cleaninline{Main} box.
204 The definition of the type class and the instances for an example interpretation (\cleaninline{:: Inter}) are as follows:
205
206 \begin{lstClean}[caption={Functions in \gls{MTASK}.}]
207 class fun a v :: ((a -> v s) -> In (a -> v s) (Main (MTask v u)))
208 -> Main (MTask v u)
209
210 instance fun () Inter where ...
211 instance fun (Inter a) Inter | type a where ...
212 instance fun (Inter a, Inter b) Inter | type a, type b where ...
213 instance fun (Inter a, Inter b, Inter c) Inter | type a, ... where ...
214 ...
215 \end{lstClean}
216
217 Deriving how to define and use functions from the type is quite the challenge even though the resulting syntax is made easier using the infix type \cleaninline{In}.
218 \Cref{lst:function_examples} show the factorial function, a tail-call optimised factorial function and a function with zero arguments to demonstrate the syntax.
219 Splitting out the function definition for each single arity means that that for every function arity and combination of arguments, a separate class constraint must be created.
220 Many of the often used functions are already bundled in the \cleaninline{mtask} class constraint collection.
221 \cleaninline{factorialtail} shows a manually added class constraint.
222 Definiting zero arity functions is shown in the \cleaninline{zeroarity} expression.
223 Finally, \cleaninline{swapTuple} shows an example of a tuple being swapped.
224
225 % VimTeX: SynIgnore on
226 \begin{lstClean}[label={lst:function_examples},caption={Function examples in \gls{MTASK}.}]
227 factorial :: Main (v Int) | mtask v
228 factorial =
229 fun \fac=(\i->if' (i <. lit 1)
230 (lit 1)
231 (i *. fac (i -. lit 1)))
232 In {main = fac (lit 5) }
233
234 factorialtail :: Main (v Int) | mtask v & fun (v Int, v Int) v
235 factorialtail =
236 fun \facacc=(\(acc, i)->if' (i <. lit 1)
237 acc
238 (fac (acc *. i, i -. lit 1)))
239 In fun \fac=(\i->facacc (lit 1, i))
240 In {main = fac (lit 5) }
241
242 zeroarity :: Main (v Int) | mtask v
243 zeroarity =
244 fun \fourtytwo=(\()->lit 42)
245 In fun \add=(\(x, y)->x +. y)
246 In {main = add (fourtytwo (), lit 9)}
247
248 swapTuple :: Main (v (Int, Bool)) | mtask v
249 swapTuple =
250 fun \swap=(tupopen \(x, y)->tupl y x)
251 In {main = swap (tupl true (lit 42)) }
252 \end{lstClean}
253 % VimTeX: SynIgnore off
254
255 \section{Tasks and task combinators}\label{sec:top}
256 This section describes \gls{MTASK}'s task language.
257 \Gls{MTASK}'s task language can be divided into three categories, namely
258 \begin{enumerate*}
259 \item Basic tasks, in most \gls{TOP} systems, the basic tasks are called editors, modelling the interactivity with the user.
260 In \gls{MTASK}, there are no \emph{editors} in that sense but there is interaction with the outside world through microcontroller peripherals such as sensors and actuators.
261 \item Task combinators provide a way of describing the workflow.
262 They combine one or more tasks into a compound task.
263 \item \glspl{SDS} in \gls{MTASK} can be seen as references to data that can be shared using many-to-many communication and are only accessible from within the task language to ensure atomicity.
264 \end{enumerate*}
265
266 As \gls{MTASK} is integrated with \gls{ITASK}, the same stability distinction is made for task values.
267 A task in \gls{MTASK} is denoted by the \gls{DSL} type synonym shown in \cref{lst:task_type}, an expression of the type \cleaninline{TaskValue a} in interpretation \cleaninline{v}.
268
269 \begin{lstClean}[label={lst:task_type},caption={Task type in \gls{MTASK}.}]
270 :: MTask v a :== v (TaskValue a)
271
272 // From the iTask library
273 :: TaskValue a
274 = NoValue
275 | Value a Bool
276 \end{lstClean}
277
278 \subsection{Basic tasks}
279 The most rudimentary basic tasks are the \cleaninline{rtrn} and \cleaninline{unstable} tasks.
280 They lift the value from the \gls{MTASK} expression language to the task domain either as a stable value or an unstable value.
281 There is also a special type of basic task for delaying execution.
282 The \cleaninline{delay} task---given a number of milliseconds---yields an unstable value while the time has not passed.
283 Once the specified time has passed, the time it overshot the planned time is yielded as a stable task value.
284 See \cref{sec:repeat} for an example task using \cleaninline{delay}.
285
286 \begin{lstClean}[label={lst:basic_tasks},caption={Function examples in \gls{MTASK}.}]
287 class rtrn v :: (v t) -> MTask v t
288 class unstable v :: (v t) -> MTask v t
289 class delay v :: (v n) -> MTask v n | long v n
290 \end{lstClean}
291
292 \subsubsection{Peripherals}\label{sssec:peripherals}
293 For every sensor or actuator, basic tasks are available that allow interaction with the specific peripheral.
294 The type classes for these tasks are not included in the \cleaninline{mtask} class collection as not all devices nor all language interpretations have such peripherals connected.
295
296 \Cref{lst:dht,lst:gpio} show the type classes for \glspl{DHT} sensors and \gls{GPIO} access.
297 Other peripherals have similar interfaces, they are available in the \cref{sec:aux_peripherals}.
298 For the \gls{DHT} sensor there are two basic tasks, \cleaninline{temperature} and \cleaninline{humidity}, that---will given a \cleaninline{DHT} object---produce a task that yields the observed temperature in \unit{\celcius} or relative humidity as a percentage as an unstable value.
299 Currently, two different types of \gls{DHT} sensors are supported, the \emph{DHT} family of sensors connect through $1$-wire protocol and the \emph{SHT} family of sensors connected using \gls{I2C} protocol.
300 Creating such a \cleaninline{DHT} object is very similar to creating functions in \gls{MTASK} and uses \gls{HOAS} to make it type safe.
301
302 \begin{lstClean}[label={lst:dht},caption={The \gls{MTASK} interface for \glspl{DHT} sensors.}]
303 :: DHT //abstract
304 :: DHTInfo
305 = DHT_DHT Pin DHTtype
306 | DHT_SHT I2CAddr
307 :: DHTtype = DHT11 | DHT21 | DHT22
308 class dht v where
309 DHT :: DHTInfo ((v DHT) -> Main (v b)) -> Main (v b) | type b
310 temperature :: (v DHT) -> MTask v Real
311 humidity :: (v DHT) -> MTask v Real
312
313 measureTemp :: Main (MTask v Real) | mtask v & dht v
314 measureTemp = DHT (DHT_SHT (i2c 0x36)) \dht->
315 {main=temperature dht}
316 \end{lstClean}
317
318 \Gls{GPIO} access is divided into three classes: analog, digital and pin modes (see \cref{lst:gpio}).
319 For all pins and pin modes an \gls{ADT} is available that enumerates the pins.
320 The analog \gls{GPIO} pins of a microcontroller are connected to an \gls{ADC} that translates the voltage to an integer.
321 Analog \gls{GPIO} pins can be either read or written to.
322 Digital \gls{GPIO} pins only report a high or a low value.
323 The \cleaninline{pin} type class allows functions to be overloaded in either the analog or digital pins, e.g.\ analog pins can be considered as digital pins as well.
324
325 For digital \gls{GPIO} interaction, the \cleaninline{dio} type class is used.
326 The first argument of the functions in this class is overloaded, i.e.\ it accepts either an \cleaninline{APin} or a \cleaninline{DPin}.
327 Analog \gls{GPIO} tasks are bundled in the \cleaninline{aio} type class.
328 \Gls{GPIO} pins usually operate according to a certain pin mode that states whether the pin acts as an input pin, an input with an internal pull-up resistor or an output pin.
329 This setting can be applied using the \cleaninline{pinMode} class by hand or by using the \cleaninline{declarePin} \gls{GPIO} pin constructor.
330 Setting the pin mode is a task that immediately finisheds and fields a stable unit value.
331 Writing to a pin is also a task that immediately finishes but yields the written value instead.
332 Reading a pin is a task that yields an unstable value---i.e.\ the value read from the actual pin.
333
334 \begin{lstClean}[label={lst:gpio},caption={The \gls{MTASK} interface for \gls{GPIO} access.}]
335 :: APin = A0 | A1 | A2 | A3 | A4 | A5
336 :: DPin = D0 | D1 | D2 | D3 | D4 | D5 | D6 | D7 | D8 | D9 | D10 | ...
337 :: PinMode = PMInput | PMOutput | PMInputPullup
338 :: Pin = AnalogPin APin | DigitalPin DPin
339
340 class pin p :: p -> Pin
341 instance pin APin, DPin
342
343 class aio v where
344 writeA :: (v APin) (v Int) -> MTask v Int
345 readA :: (v APin) -> MTask v Int
346
347 class dio p v | pin p where
348 writeD :: (v p) (v Bool) -> MTask v Bool
349 readD :: (v p) -> MTask v Bool | pin p
350
351 class pinMode v where
352 pinMode :: (v PinMode) (v p) -> MTask v () | pin p
353 declarePin :: p PinMode ((v p) -> Main (v a)) -> Main (v a) | pin p
354 \end{lstClean}
355
356 \Cref{lst:gpio_examples} shows two examples of \gls{MTASK} tasks using \gls{GPIO} pins.
357 \cleaninline{task1} reads analog \gls{GPIO} pin 3.
358 This is a task that never terminates.
359 \cleaninline{task2} writes the \cleaninline{true} (\gls{ARDUINO} \arduinoinline{HIGH}) value to digital \gls{GPIO} pin 3.
360 This task finishes immediately after writing to the pin.
361
362 \begin{lstClean}[label={lst:gpio_examples},caption={\Gls{GPIO} example in \gls{MTASK}.}]
363 task1 :: MTask v Int | mtask v
364 task1 = declarePin A3 PMInput \a3->{main=readA a3}
365
366 task2 :: MTask v Int | mtask v
367 task2 = declarePin D3 PMOutput \d3->{main=writeD d3 true}
368 \end{lstClean}
369
370 \subsection{Task combinators}
371 Task combinators are used to combine multiple tasks to describe workflows.
372 In contrast to \gls{ITASK}, that uses super combinators to derive the simpler ones, \gls{MTASK} has a set of simpler combinators from which more complicated workflow can be derived.
373 There are three main types of task combinators, namely:
374 \begin{enumerate*}
375 \item Sequential combinators that execute tasks one after the other, possibly using the result of the left hand side.
376 \item Parallel combinators that execute tasks at the same time combining the result.
377 \item Miscellaneous combinators that change the semantics of a task---e.g.\ repeat it or delay execution.
378 \end{enumerate*}
379
380 \subsubsection{Sequential}
381 Sequential task combination allows the right-hand side task to observe the left-hand side task value.
382 All seqential task combinators are expressed in the \cleaninline{expr} class and can be---and are by default---derived from the Swiss army knife step combinator \cleaninline{>>*.}.
383 This combinator has a single task on the left-hand side and a list of \emph{task continuations} on the right-hand side.
384 The list of task continuations is checked every rewrite step and if one of the predicates matches, the task continues with the result of this combination.
385 \cleaninline{>>=.} is a shorthand for the bind operation, if the left-hand side is stable, the right-hand side function is called to produce a new task.
386 \cleaninline{>>\|.} is a shorthand for the sequence operation, if the left-hand side is stable, it continues with the right-hand side task.
387 The \cleaninline{>>~.} and \cleaninline{>>..} combinators are variants of the ones above that ignore the stability and continue on an unstable value as well.
388
389 \begin{lstClean}[label={lst:mtask_sequential},caption={Sequential task combinators in \gls{MTASK}.}]
390 class step v | expr v where
391 (>>*.) infixl 1 :: (MTask v t) [Step v t u] -> MTask v u
392 (>>=.) infixl 0 :: (MTask v t) ((v t) -> MTask v u) -> MTask v u
393 (>>|.) infixl 0 :: (MTask v t) (MTask v u) -> MTask v u
394 (>>~.) infixl 0 :: (MTask v t) ((v t) -> MTask v u) -> MTask v u
395 (>>..) infixl 0 :: (MTask v t) (MTask v u) -> MTask v u
396
397 :: Step v t u
398 = IfValue ((v t) -> v Bool) ((v t) -> MTask v u)
399 | IfStable ((v t) -> v Bool) ((v t) -> MTask v u)
400 | IfUnstable ((v t) -> v Bool) ((v t) -> MTask v u)
401 | Always (MTask v u)
402 \end{lstClean}
403
404 The following listing shows an example of a step in action.
405 The \cleaninline{readPinBin} function produces an \gls{MTASK} task that classifies the value of an analogue pin into four bins.
406 It also shows that the nature of embedding allows the host language to be used as a macro language.
407 Furthermore
408
409 \begin{lstClean}[label={lst:mtask_readpinbin},caption={Read an analog pin and bin the value in \gls{MTASK}.}]
410 readPinBin :: Int -> Main (MTask v Int) | mtask v
411 readPinBin lim = declarePin PMInput A2 \a2->
412 { main = readA a2 >>*.
413 [ IfValue (\x->x <. lim) (\_->rtrn (lit bin))
414 \\ lim <-[64,128,192,256]
415 & bin <- [0..]]}
416 \end{lstClean}
417
418 \subsubsection{Parallel}\label{sssec:combinators_parallel}
419 The result of a parallel task combination is a compound that actually executes the tasks at the same time.
420 There are two types of parallel task combinators (see \cref{lst:mtask_parallel}).
421
422 \begin{lstClean}[label={lst:mtask_parallel},caption={Parallel task combinators in \gls{MTASK}.}]
423 class (.&&.) infixr 4 v :: (MTask v a) (MTask v b) -> MTask v (a, b)
424 class (.||.) infixr 3 v :: (MTask v a) (MTask v a) -> MTask v a
425 \end{lstClean}
426
427 The conjunction combinator (\cleaninline{.&&.}) combines the result by putting the values from both sides in a tuple.
428 The stability of the task depends on the stability of both children.
429 If both children are stable, the result is stable, otherwise the result is unstable.
430 The disjunction combinator (\cleaninline{.\|\|.}) combines the results by picking the leftmost, most stable task.
431 The semantics are most easily described using the \gls{CLEAN} functions shown in \cref{lst:semantics_con,lst:semantics_dis}.
432
433 \begin{figure}[ht]
434 \centering
435 \begin{subfigure}[t]{.5\textwidth}
436 \begin{lstClean}[caption={Semantics of the\\conjunction combinator.},label={lst:semantics_con}]
437 con :: (TaskValue a) (TaskValue b)
438 -> TaskValue (a, b)
439 con NoValue r = NoValue
440 con l NoValue = NoValue
441 con (Value l ls) (Value r rs)
442 = Value (l, r) (ls && rs)
443
444 \end{lstClean}
445 \end{subfigure}%
446 \begin{subfigure}[t]{.5\textwidth}
447 \begin{lstClean}[caption={Semantics of the\\disjunction combinator.},label={lst:semantics_dis}]
448 dis :: (TaskValue a) (TaskValue a)
449 -> TaskValue a
450 dis NoValue r = r
451 dis l NoValue = l
452 dis (Value l ls) (Value r rs)
453 | rs = Value r True
454 | otherwise = Value l ls
455 \end{lstClean}
456 \end{subfigure}
457 \end{figure}
458
459 \Cref{lst:mtask_parallel_example} gives an example program using the parallel task combinator.
460 This program will read two pins at the same time, returning when one of the pins becomes \arduinoinline{HIGH}.
461 If the combinator was the \cleaninline{.&&.} instead, the type would be \cleaninline{MTask v (Bool, Bool)} and the task would only return when both pins have been \arduinoinline{HIGH} but not necessarily at the same time.
462
463 \begin{lstClean}[label={lst:mtask_parallel_example},caption={Parallel task combinator example in \gls{MTASK}.}]
464 task :: MTask v Bool
465 task =
466 declarePin D0 PMInput \d0->
467 declarePin D1 PMInput \d1->
468 let monitor pin = readD pin >>*. [IfValue (\x->x) \x->rtrn x]
469 In {main = monitor d0 .||. monitor d1}
470 \end{lstClean}
471
472 \subsubsection{Repeat}\label{sec:repeat}
473 The \cleaninline{rpeat} combinator executes the child task.
474 If a stable value is observed, the task is reinstated.
475 The functionality of \cleaninline{rpeat} can also be simulated by using functions and sequential task combinators and even made to be stateful as can be seen in \cref{lst:blinkthreadmtask}.
476
477 \begin{lstClean}[label={lst:mtask_repeat},caption={Repeat task combinators in \gls{MTASK}.}]
478 class rpeat v where
479 rpeat :: (MTask v a) -> MTask v a
480 \end{lstClean}
481
482 To demonstrate the combinator, \cref{lst:mtask_repeat_example} show \cleaninline{rpeat} in use.
483 This task will mirror the value read from analog \gls{GPIO} pin \cleaninline{A1} to pin \cleaninline{A2} by constantly reading the pin and writing the result.
484
485 \begin{lstClean}[label={lst:mtask_repeat_example},caption={Exemplary repeat task in \gls{MTASK}.}]
486 task :: MTask v Int | mtask v
487 task =
488 declarePin A1 PMInput \a1->
489 declarePin A2 PMOutput \a2->
490 {main = rpeat (readA a1 >>~. writeA a2 >>|. delay (lit 1000))}
491 \end{lstClean}
492
493 \subsection{\texorpdfstring{\Glsxtrlongpl{SDS}}{Shared data sources}}
494 \Glspl{SDS} in \gls{MTASK} are by default references to shared memory but can also be references to \glspl{SDS} in \gls{ITASK} (see \cref{sec:liftsds}).
495 Similar to peripherals (see \cref{sssec:peripherals}), they are constructed at the top level and are accessed through interaction tasks.
496 The \cleaninline{getSds} task yields the current value of the \gls{SDS} as an unstable value.
497 This behaviour is similar to the \cleaninline{watch} task in \gls{ITASK}.
498 Writing a new value to \pgls{SDS} is done using \cleaninline{setSds}.
499 This task yields the written value as a stable result after it is done writing.
500 Getting and immediately after setting \pgls{SDS} is not necessarily an \emph{atomic} operation in \gls{MTASK} because it is possible that another task accesses the \gls{SDS} in between.
501 To circumvent this issue, \cleaninline{updSds} is created, this task atomically updates the value of the \gls{SDS}.
502 The \cleaninline{updSds} task only guarantees atomicity within \gls{MTASK}.
503
504 \begin{lstClean}[label={lst:mtask_sds},caption={\Glspl{SDS} in \gls{MTASK}.}]
505 :: Sds a // abstract
506 class sds v where
507 sds :: ((v (Sds t)) -> In t (Main (MTask v u))) -> Main (MTask v u)
508 getSds :: (v (Sds t)) -> MTask v t
509 setSds :: (v (Sds t)) (v t) -> MTask v t
510 updSds :: (v (Sds t)) ((v t) -> v t) -> MTask v t
511 \end{lstClean}
512
513 \Cref{lst:mtask_sds_examples} shows an example using \glspl{SDS}.
514 The \cleaninline{count} function takes a pin and returns a task that counts the number of times the pin is observed as high by incrementing the \cleaninline{share} \gls{SDS}.
515 In the \cleaninline{main} expression, this function is called twice and the results are combined using the parallel or combinator (\cleaninline{.\|\|.}).
516 Using a sequence of \cleaninline{getSds} and \cleaninline{setSds} would be unsafe here because the other branch might write their old increment value immediately after writing, effectively missing a count.\todo{beter opschrijven}
517
518 \begin{lstClean}[label={lst:mtask_sds_examples},caption={Examples with \glspl{SDS} in \gls{MTASK}.}]
519 task :: MTask v Int | mtask v
520 task = declarePin D3 PMInput \d3->
521 declarePin D5 PMInput \d5->
522 sds \share=0
523 In fun \count=(\pin->
524 readD pin
525 >>* [IfValue (\x->x) (\_->updSds (\x->x +. lit 1) share)]
526 >>| delay (lit 100) // debounce
527 >>| count pin)
528 In {main=count d3 .||. count d5}
529 \end{lstClean}
530
531 \section{Conclusion}
532 \Gls{MTASK} is a rich \gls{TOP} language tailored for \gls{IOT} systems.
533 It is embedded in the pure functional language \gls{CLEAN} and uses an enriched lambda calculus as a host language.
534 It provides support for all common arithmetic expressions, conditionals, functions, but also several basic tasks, task combinators, peripheral support and integration with \gls{ITASK}.
535 By embedding domain-specific knowledge in the language itself, it achieves the same abstraction level and dynamicity as other \gls{TOP} languages while targetting tiny computers instead.
536 As a result, a single declarative specification can describe an entire \gls{IOT} system.
537
538 \input{subfilepostamble}
539 \end{document}