09b4f2b01da4c7d10c91290c03d908336bcc6c6f
[phd-thesis.git] / top / lang.tex
1 \documentclass[../thesis.tex]{subfiles}
2
3 \input{subfilepreamble}
4
5 \setcounter{chapter}{3}
6
7 \begin{document}
8 \input{subfileprefix}
9 \chapter{The \texorpdfstring{\gls{MTASK}}{mTask} language}%\texorpdfstring{\glsxtrshort{DSL}}{DSL}}%
10 \label{chp:mtask_dsl}
11 \begin{chapterabstract}
12 This chapter introduces the \gls{TOP} language \gls{MTASK} by:
13 \begin{itemize}
14 \item introducing the setup of the language;
15 \item describing briefly the various interpretations;
16 \item and showing the language interface for:
17 \begin{itemize}
18 \item the types;
19 \item expressions, datatypes, and functions;
20 \item tasks and task combinators;
21 \item and \glspl{SDS}.
22 \end{itemize}
23 \end{itemize}
24 \end{chapterabstract}
25
26 The \gls{MTASK} system is a complete \gls{TOP} programming environment for programming microcontrollers.
27 This means that it not only contains a \gls{TOP} language but also a \gls{TOP} engine.
28 Due to the nature of the embedding technique, it is possible to have multiple interpretations for programs written in the \gls{MTASK} language.
29 It is implemented as an \gls{EDSL} in \gls{CLEAN} using class-based---or tagless-final---embedding.
30 This means that the language interface, i.e.\ the language constructs, are a collection of type classes.
31 Interpretations of this interface are data types implementing these classes.
32 This particular type of embedding results in the language being is extensible both in language constructs and in intepretations.
33 Adding a language construct is as simple as adding a type class and adding an interpretation is done by creating a new data type and providing implementations for the various type classes.
34 Let us illustrate this technique by taking the very simple language of literal values.
35 This language interface can be described using a single type constructor class with a single function \cleaninline{lit}.
36 This function is for lifting a values, as long as it has a \cleaninline{toString} instance, from the host language to our new \gls{DSL}.
37 The type variable \cleaninline{v} of the type class represents the view on the language, the interpretation.
38
39 \begin{lstClean}
40 class literals v where
41 lit :: a -> v a | toString a
42 \end{lstClean}
43
44 Providing an evaluator is straightforward as can be seen in the following listing.
45 The evaluator is just a box holding a value of the computation but it can also be something more complex such as a monadic computation.
46
47 \begin{lstClean}
48 :: Eval a = Eval a
49
50 runEval :: (Eval a) -> a
51 runEval (Eval a) = a
52
53 instance literals Eval where
54 lit a = Eval a
55 \end{lstClean}
56
57 Extending our language with a printer happens by defining a new data type and providing instances for the type constructor classes.
58 The printer shown below only stores a printed representation and hence the type is just a phantom type:
59
60 \begin{lstClean}
61 :: Printer a = Printer String
62
63 runPrinter :: (Printer a) -> String
64 runPrinter (Printer a) = a
65
66 instance literals Printer where
67 lit a = Printer (toString a)
68 \end{lstClean}
69
70 Adding language constructs happens by defining new type classes and giving implementations for the interpretations.
71 The following listing adds an addition construct to the language and shows the implementations for the evaluator and printer.
72
73 \begin{lstClean}
74 class addition v where
75 add :: v a -> v a -> v a | + a
76
77 instance addition Eval where
78 add (Eval l) (Eval r) = Eval (l + r)
79
80 instance addition Printer where
81 add (Printer l) (Printer r) = Printer ("(" +++ l +++ "+" +++ r +++ ")")
82 \end{lstClean}
83
84 Terms in our toy language can be overloaded in their interpretation, they are just an interface.
85 For example, $1+5$ is written as \cleaninline{add (lit 1) (lit 5)} and has the type \cleaninline{v Int \| literals, addition v}.
86 However, due to the way polymorphism is implemented in most functional languages, it is not always straightforward to use multiple interpretations in one function.
87 Creating such a function, e.g.\ one that both prints and evaluates an expression, requires rank-2 polymorphism (see \cref{lst:rank2_mtask}).
88
89 \section{Interpretations}
90 This section describes all the interpretations tha the \gls{MTASK} language has.
91 Not all of these interpretations are necessarily \gls{TOP} engines, i.e.\ not all of the interpretations execute the resulting tasks.
92 Some may perform an analysis over the program or typeset the program so that a textual representation can be shown.
93
94 \subsection{Pretty printer}
95 The pretty printer interpretation converts the expression to a string representation.
96 As the host language \gls{CLEAN} constructs the \gls{MTASK} expressions at run time, it can be useful to show the constructed expression at run time as well.
97 The only function exposed for this interpretation is the \cleaninline{showMain} function (\cref{lst:showmain}).
98 It runs the pretty printer and returns a list of strings containing the pretty printed result.
99 The pretty printing function does the best it can but obviously cannot reproduce the layout, curried functions, and variable names.
100 This shortcoming is illustrated by printing a blink task that contains a function and currying in \cref{lst:showexample}.
101
102 \begin{lstClean}[caption={The entrypoint for the pretty printing interpretation.},label={lst:showmain}]
103 :: Show a // from the mTask pretty printing library
104 showMain :: (Main (Show a)) -> [String] | type a
105 \end{lstClean}
106
107 \begin{lstClean}[caption={Pretty printing interpretation example.},label={lst:showexample}]
108 blinkTask :: Main (MTask v Bool) | mtask v
109 blinkTask =
110 fun \blink=(\state->
111 writeD d13 state >>|. delay (lit 500) >>=. blink o Not
112 ) In {main = blink true}
113
114 // output:
115 // fun f0 a1 = writeD(D13, a1) >>= \a2.(delay 1000)
116 // >>| (f0 (Not a1)) in (f0 True)
117 \end{lstClean}
118
119 \subsection{Simulator}
120 The simulator converts the expression to a ready-for-work \gls{ITASK} simulation.
121 The task resulting from the \cleaninline{simulate} function presents the user with an interactive simulation environment (see \cref{lst:simulatemain,fig:sim}).
122 The simulation allows the user to (partially) execute tasks, control the simulated peripherals, inspect the internal state of the tasks, and interact with \glspl{SDS}.
123
124 \begin{lstClean}[caption={The entrypoint for the simulation interpretation.},label={lst:simulatemain}]
125 :: TraceTask a // from the mTask simulator library
126 simulate :: (Main (TraceTask a)) -> [String] | type a
127 \end{lstClean}
128
129 \begin{figure}
130 \centering
131 \includegraphics[width=\linewidth]{simg}
132 \caption{Simulator interface for the blink program.}\label{fig:sim}
133 \end{figure}
134
135 \subsection{Byte code compiler}
136 The main interpretation of the \gls{MTASK} system is the byte code compiler (\cleaninline{:: BCInterpret}).
137 With it, and a handful of integration functions and tasks, \gls{MTASK} tasks can be executed on microcontrollers and integrated in \gls{ITASK} as if they were regular \gls{ITASK} tasks.
138 Furthermore, with a special language construct, \glspl{SDS} can be shared between \gls{MTASK} and \gls{ITASK} programs as well.
139 For this chapter, the focus lies on the language itself.
140 The integration with \gls{ITASK} is explained thoroughly later in \cref{chp:integration_with_itask}.
141
142 When using the byte code compiler interpretation in conjunction with the \gls{ITASK} integration, \gls{MTASK} is a heterogeneous \gls{DSL}.
143 I.e.\ some components---for example the \gls{RTS} on the microcontroller that executes the tasks---is largely unaware of the other components in the system, and it is executed on a completely different architecture.
144 The \gls{MTASK} language is based on a simply-typed $\lambda$-calculus with support for some basic types, arithmetic operations, and function definitions.
145 This basic language is enriched with a task language to make it \gls{TOP} (see \cref{sec:top}).
146
147 \section{Types}
148 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.
149 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.
150 The most used class constraint is the \cleaninline{type} class collection containing functions for serialization, printing, \gls{ITASK} constraints, \etc.
151 Many of these functions are usually automatically derived using generic programming but can be specialised when needed.
152 An even stronger restriction on types is defined for types that have a stack representation.
153 This \cleaninline{basicType} class has instances for many \gls{CLEAN} basic types such as \cleaninline{Int}, \cleaninline{Real} and \cleaninline{Bool}.
154 The class constraints for values in \gls{MTASK} are omnipresent in all functions and therefore usually omitted throughout throughout the chapters for brevity and clarity.
155
156 \begin{table}[ht]
157 \centering
158 \caption{Translation from \cmtask{} data types to \ccpp{} datatypes.}%
159 \label{tbl:mtask-c-datatypes}
160 \begin{tabular}{lll}
161 \toprule
162 \cmtask{} & \ccpp{} type & \textnumero{}bits\\
163 \midrule
164 \cleaninline{Bool} & \cinline{bool} & 16\\
165 \cleaninline{Char} & \cinline{char} & 16\\
166 \cleaninline{Int} & \cinline{int16_t} & 16\\
167 \cleaninline{Real} & \cinline{float} & 32\\
168 \cleaninline{:: Long} & \cinline{int32_t} & 32\\
169 \cleaninline{:: T = A \| B \| C} & \cinline{enum} & 16\\
170 \bottomrule
171 \end{tabular}
172 \end{table}
173
174 \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.
175 The \gls{MTASK} language interface consists of a core collection of type classes bundled in the type class \cleaninline{class mtask}.
176 Every interpretation implements the type classes in the \cleaninline{mtask} class
177 There are also \gls{MTASK} extensions that not every interpretation implements and are thus not included in the \cleaninline{mtask} class collection such as peripherals and \gls{ITASK} integration.
178
179 \begin{lstClean}[caption={Classes and class collections for the \gls{MTASK} language.},label={lst:constraints}]
180 class type t | iTask, ... , fromByteCode, toByteCode t
181 class basicType t | type t where ...
182
183 class mtask v | expr, ..., int, real, long v
184 \end{lstClean}
185
186 Peripheral, \gls{SDS}, and function definitions are always defined at the top level.
187 This is enforced by the \cleaninline{Main} type.
188 Most top level definitions, such as functions, are defined using \gls{HOAS}.
189 To make their syntax friendlier, the \cleaninline{In} type---an infix tuple---is used to combine these top level definitions.
190 An example of this can be seen in \cleaninline{someTask} shown in \cref{lst:mtask_types}.
191
192 % VimTeX: SynIgnore on
193 \begin{lstClean}[caption={Example task and auxiliary types in the \gls{MTASK} language.},label={lst:mtask_types}]
194 // From the mTask library
195 :: Main a = { main :: a }
196 :: In a b = (In) infix 0 a b
197
198 someTask :: MTask v Int | mtask v & liftsds v & sensor1 v & ...
199 someTask =
200 sensor1 config1 \sns1->
201 sensor2 config2 \sns2->
202 sds \s1 = initialValue
203 In liftsds \s2 = someiTaskSDS
204 In fun \fun1= ( \(a0, a1)->... )
205 In fun \fun2= ( \a->... )
206 In { main = mainexpr }
207 \end{lstClean}
208 % VimTeX: SynIgnore off
209
210 Expressions in the \gls{MTASK} language are usually overloaded in their interpretation (\cleaninline{v}).
211 In \gls{CLEAN}, all free variables in a type are implicitly universally quantified.
212 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}.
213 \Cref{lst:rank2_mtask} shows an example of a function that simulates an \gls{MTASK} expression while showing the pretty printed representation in parallel.
214 Providing a type for the \cleaninline{simulateAndPrint} function is mandatory as the compiler cannot infer the type of rank-2 polymorphic functions.
215
216 \begin{lstClean}[label={lst:rank2_mtask},caption={Rank-2 polymorphism to allow multiple interpretations}]
217 simulateAndPrint :: (A.v: Main (MTask v a) | mtask v) -> Task a | type a
218 simulateAndPrint mt =
219 simulate mt
220 -|| Hint "Current task:" @>> viewInformation [] (showMain mt)
221 \end{lstClean}
222
223 \section{Expressions}\label{sec:expressions}
224 This section shows all \gls{MTASK} constructs for exppressions.
225 \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 numeric and boolean arithmetics; do comparisons; and conditional execution.
226 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.
227
228 \begin{lstClean}[caption={The \gls{MTASK} class for expressions},label={lst:expressions}]
229 class expr v where
230 lit :: t -> v t | type t
231 (+.) infixl 6 :: (v t) (v t) -> v t | basicType, +, zero t
232 ...
233 (&.) infixr 3 :: (v Bool) (v Bool) -> v Bool
234 (|.) infixr 2 :: (v Bool) (v Bool) -> v Bool
235 Not :: (v Bool) -> v Bool
236 (==.) infix 4 :: (v a) (v a) -> v Bool | Eq, basicType a
237 ...
238 If :: (v Bool) (v t) (v t) -> v t | type t
239 \end{lstClean}
240
241 Conversion to-and-fro data types is available through the overloaded functions \cleaninline{int}, \cleaninline{long} and \cleaninline{real}.
242 These functions convert the argument to the respective type similar to casting in \gls{C}.
243 For most interpretations, there are instances of these classes for all numeric types.
244
245 \begin{lstClean}[caption={Type conversion functions in \gls{MTASK}.}]
246 class int v a :: (v a) -> v Int
247 class real v a :: (v a) -> v Real
248 class long v a :: (v a) -> v Long
249 \end{lstClean}
250
251 Values from the host language must be explicitly lifted to the \gls{MTASK} language using the \cleaninline{lit} function.
252 For convenience, there are many lower-cased macro definitions for often used constants such as \cleaninline{true :== lit True}, \cleaninline{false :== lit False}.
253
254 \Cref{lst:example_exprs} shows some examples of expressions in the language.
255 Since they are only expressions, there is no need for a \cleaninline{Main}.
256 \cleaninline{e0} defines the literal \num{42}, \cleaninline{e1} calculates the literal \num{42.0} using real numbers.
257 \cleaninline{e2} compares \cleaninline{e0} and \cleaninline{e1} as integers and if they are equal it returns $\frac{\text{\cleaninline{e2}}}{2}$ and \cleaninline{e0} otherwise.
258
259 \begin{lstClean}[label={lst:example_exprs},caption={Example \gls{MTASK} expressions.}]
260 e0 :: v Int | expr v
261 e0 = lit 42
262
263 e1 :: v Real | expr v
264 e1 = lit 38.0 +. real (lit 4)
265
266 e2 :: v Int | expr v
267 e2 = If (e0 ==. int e1)
268 (int e1 /. lit 2) e0
269 \end{lstClean}
270
271 The \gls{MTASK} language is shallowly embedded in \gls{CLEAN} and the terms are constructed at run time.
272 This means that \gls{MTASK} programs can also be tailor-made at run time or constructed using \gls{CLEAN} functions maximising the linguistic reuse \citep{krishnamurthi_linguistic_2001}.
273 The \cleaninline{approxEqual} function in \cref{lst:example_macro} performs a simple approximate equality---admittedly not taking into account all floating point pecularities.
274 When calling \cleaninline{approxEqual} in an \gls{MTASK} expression, the resulting code is inlined.
275
276 \begin{lstClean}[label={lst:example_macro},caption={Approximate equality as an example of linguistic reuse in \gls{MTASK}.}]
277 approxEqual :: (v Real) (v Real) (v Real) -> v Real | expr v
278 approxEqual x y eps = If (x ==. y) true
279 ( If (x >. y)
280 (x -. y <. eps)
281 (y -. x <. eps)
282 )
283 \end{lstClean}
284
285 \subsection{Data types}
286 Most of \gls{CLEAN}'s fixed-size basic types are mapped on \gls{MTASK} types (see \cref{tbl:mtask-c-datatypes}).
287 However, it is useful to have access to compound types as well.
288 All types in \gls{MTASK} must have a fixed-size representation on the stack so sum types are not (yet) supported.
289 While it is possible to lift any 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}).
290 To be able to use types as first-class citizens, constructors, and field selectors or deconstructors are required (see \cref{chp:first-class_datatypes}).
291 \Cref{lst:tuple_exprs} shows the scaffolding for supporting tuples in \gls{MTASK}.
292 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, a deconstructor.
293 Examples for using tuples can be found later in \cref{sec:mtask_functions}.
294
295 \begin{lstClean}[label={lst:tuple_exprs},caption={Tuple constructor and field selectors in \gls{MTASK}.}]
296 class tupl v where
297 tupl :: (v a) (v b) -> v (a, b) | type a & type b
298 first :: (v (a, b)) -> v a | type a & type b
299 second :: (v (a, b)) -> v b | type a & type b
300
301 tupopen f :== \v->f (first v, second v)
302 \end{lstClean}
303
304 \subsection{Functions}\label{sec:mtask_functions}
305 Adding functions to the language is achieved by one type class to the \gls{DSL}.
306 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}.
307 The \gls{MTASK} language only allows first-order functions and does not allow partial function application.
308 This is restricted by using a multi-parameter type class where the first parameter represents the arguments and the second parameter the view or interpretation.
309 An instance is provided for each function arity instead of providing an instance for all possible arities to enforce that all functions are first order.
310 By using tuples for the arguments, partial function applications is eradicated.
311 The definition of the type class and the some instances for the pretty printer are as follows:
312
313 \begin{lstClean}[caption={Functions in \gls{MTASK}.}]
314 class fun a v :: ((a -> v s) -> In (a -> v s) (Main (MTask v u)))
315 -> Main (MTask v u)
316
317 instance fun () Show where ...
318 instance fun (Show a) Show | type a where ...
319 instance fun (Show a, Show b) Show | type a, type b where ...
320 instance fun (Show a, Show b, Show c) Show | type a, ... where ...
321 ...
322 \end{lstClean}
323
324 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}.
325 \Cref{lst:function_examples} show some examples of functions to demonstrate the syntax for functions.
326 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.
327 Many of the often used functions are already bundled in the \cleaninline{mtask} class constraint collection.
328 The \cleaninline{factorial} functions shows a recursive version of the factorial function.
329 In the \cleaninline{factorialtail} function, a tail-call optimised version of the factorial function, a manually added class constraint can be seen.
330 Definiting zero arity functions, always called with the unit as an argument, is shown in the \cleaninline{zeroarity} expression.
331 Finally, \cleaninline{swapTuple} shows an example of a tuple being swapped.
332
333 % VimTeX: SynIgnore on
334 \begin{lstClean}[label={lst:function_examples},caption={Function examples in \gls{MTASK}.}]
335 factorial :: Main (v Int) | mtask v
336 factorial =
337 fun \fac=(\i->If (i <. lit 1)
338 (lit 1)
339 (i *. fac (i -. lit 1)))
340 In {main = fac (lit 5) }
341
342 factorialtail :: Main (v Int) | mtask v & fun (v Int, v Int) v
343 factorialtail =
344 fun \facacc=(\(acc, i)->If (i <. lit 1)
345 acc
346 (fac (acc *. i, i -. lit 1)))
347 In fun \fac=(\i->facacc (lit 1, i))
348 In {main = fac (lit 5) }
349
350 zeroarity :: Main (v Int) | mtask v
351 zeroarity =
352 fun \fourtytwo=(\()->lit 42)
353 In fun \add=(\(x, y)->x +. y)
354 In {main = add (fourtytwo (), lit 9)}
355
356 swapTuple :: Main (v (Int, Bool)) | mtask v
357 swapTuple =
358 fun \swap=(tupopen \(x, y)->tupl y x)
359 In {main = swap (tupl true (lit 42)) }
360 \end{lstClean}
361 % VimTeX: SynIgnore off
362
363 \section{Tasks and task combinators}\label{sec:top}
364 This section describes \gls{MTASK}'s task language.
365 Tasks can be seen as trees that are the result of evaluating expressions.
366 After evaluating an expression, the resulting task is executed.
367 \todo[inline]{iets zeggen over values en dat hier ook een handwavy semantiek is.}
368 The execution semantics of tasks is explained in more detail in \cref{chp:implementation}.
369 The task language of \gls{MTASK} is divided into three categories, namely
370 \begin{description}
371 \item [Basic tasks] are the leaves in the task trees.
372 In most \gls{TOP} systems, the basic tasks are called editors, modelling the interactivity with the user.
373 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.
374 \item [Task combinators] provide a way of describing the workflow.
375 They combine one or more tasks into a compound task.
376 \item [\Glspl{SDS}] are references to data in \gls{MTASK}.
377 The data is available for tasks using many-to-many communication but only from within the task language to ensure atomicity.
378 \end{description}
379
380 As \gls{MTASK} is integrated with \gls{ITASK}, a stability distinction is made for task values just as in \gls{ITASK}.
381 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}.
382
383 \begin{lstClean}[label={lst:task_type},caption={Task type in \gls{MTASK}.}]
384 :: MTask v a :== v (TaskValue a)
385
386 // From the iTask library
387 :: TaskValue a
388 = NoValue
389 | Value a Bool
390 \end{lstClean}
391
392 \subsection{Basic tasks}
393 The most rudimentary basic tasks are the \cleaninline{rtrn} and \cleaninline{unstable} tasks.
394 They lift the value from the \gls{MTASK} expression language to the task domain either as a stable value or an unstable value.
395 There is also a special type of basic task for delaying execution.
396 The \cleaninline{delay} task---given a number of milliseconds---yields an unstable value while the time has not passed.
397 Once the specified time has passed, the time it overshot the planned time is yielded as a stable task value.
398 See \cref{sec:repeat} for an example task using \cleaninline{delay}.
399
400 \begin{lstClean}[label={lst:basic_tasks},caption={Function examples in \gls{MTASK}.}]
401 class rtrn v :: (v t) -> MTask v t
402 class unstable v :: (v t) -> MTask v t
403 class delay v :: (v n) -> MTask v n | long v n
404 \end{lstClean}
405
406 \subsubsection{Peripherals}\label{sssec:peripherals}
407 For every sensor or actuator, basic tasks are available that allow interaction with the specific peripheral.
408 The type classes for these tasks are not included in the \cleaninline{mtask} class collection as not all devices nor all language interpretations support all peripherals connected.
409
410 \Cref{lst:dht} shows the type classes for \glspl{DHT} sensors.
411 Other peripherals have similar interfaces, they are available in the \cref{sec:aux_peripherals}.
412 For the \gls{DHT} sensor there are two basic tasks, \cleaninline{temperature} and \cleaninline{humidity}, that produce a task that yields the observed temperature in \unit{\celcius} or relative humidity as a percentage as an unstable value.
413 Currently, two different types of \gls{DHT} sensors are supported, the \emph{DHT} family of sensors connect through the \gls{ONEWIRE} protocol and the \emph{SHT} family of sensors connected using the \gls{I2C} protocol.
414 Creating such a \cleaninline{DHT} object is very similar to creating functions in \gls{MTASK} and uses \gls{HOAS} to make it type safe.
415
416 \begin{lstClean}[label={lst:dht},caption={The \gls{MTASK} interface for \glspl{DHT} sensors.}]
417 :: DHT //abstract
418 :: DHTInfo
419 = DHT_DHT Pin DHTtype
420 | DHT_SHT I2CAddr
421 :: DHTtype = DHT11 | DHT21 | DHT22
422 class dht v where
423 DHT :: DHTInfo ((v DHT) -> Main (v b)) -> Main (v b) | type b
424 temperature :: (v DHT) -> MTask v Real
425 humidity :: (v DHT) -> MTask v Real
426
427 measureTemp :: Main (MTask v Real) | mtask v & dht v
428 measureTemp = DHT (DHT_SHT (i2c 0x36)) \dht->
429 {main=temperature dht}
430 \end{lstClean}
431
432 \todo[inline]{Uitleggen wat GPIO is}
433 \Gls{GPIO} access is divided into three classes: analogue \gls{IO}, digital \gls{IO} and pin modes configuration (see \cref{lst:gpio}).
434 For all pins and pin modes an \gls{ADT} is available that enumerates the pins.
435 The analogue \gls{GPIO} pins of a microcontroller are connected to an \gls{ADC} that translates the measured voltage to an integer.
436 Digital \gls{GPIO} pins of a microcontroller report either a high or a low value.
437 Both analogue and digital \gls{GPIO} pins can be read or written to but it is advised to set the pin mode accordingly.
438 The \cleaninline{pin} type class allows functions to be overloaded in either the analogue or digital pins, e.g.\ analogue pins can be considered as digital pins as well.
439
440 For digital \gls{GPIO} interaction, the \cleaninline{dio} type class is used.
441 The first argument of the functions in this class is overloaded, i.e.\ it accepts either an \cleaninline{APin} or a \cleaninline{DPin}.
442 Analogue \gls{GPIO} tasks are bundled in the \cleaninline{aio} type class.
443 \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.
444 This setting can be applied using the \cleaninline{pinMode} class by hand or by using the \cleaninline{declarePin} \gls{GPIO} pin constructor.
445 Setting the pin mode is a task that immediately finisheds and fields a stable unit value.
446 Writing to a pin is also a task that immediately finishes but yields the written value instead.
447 Reading a pin is a task that yields an unstable value---i.e.\ the value read from the actual pin.
448
449 \begin{lstClean}[label={lst:gpio},caption={The \gls{MTASK} interface for \gls{GPIO} access.}]
450 :: APin = A0 | A1 | A2 | A3 | A4 | A5
451 :: DPin = D0 | D1 | D2 | D3 | D4 | D5 | D6 | D7 | D8 | D9 | D10 | ...
452 :: PinMode = PMInput | PMOutput | PMInputPullup
453 :: Pin = AnalogPin APin | DigitalPin DPin
454
455 class pin p :: p -> Pin
456 instance pin APin, DPin
457
458 class aio v where
459 writeA :: (v APin) (v Int) -> MTask v Int
460 readA :: (v APin) -> MTask v Int
461
462 class dio p v | pin p where
463 writeD :: (v p) (v Bool) -> MTask v Bool
464 readD :: (v p) -> MTask v Bool | pin p
465
466 class pinMode v where
467 pinMode :: (v PinMode) (v p) -> MTask v () | pin p
468 declarePin :: p PinMode ((v p) -> Main (v a)) -> Main (v a) | pin p
469 \end{lstClean}
470
471 \Cref{lst:gpio_examples} shows two examples of \gls{MTASK} tasks using \gls{GPIO} pins.
472 \cleaninline{task1} reads analogue \gls{GPIO} pin 3.
473 This is a task that never terminates.
474 \cleaninline{task2} writes the \cleaninline{true} (\gls{ARDUINO} \arduinoinline{HIGH}) value to digital \gls{GPIO} pin 3.
475 This task finishes immediately after writing to the pin.
476
477 \begin{lstClean}[label={lst:gpio_examples},caption={\Gls{GPIO} example in \gls{MTASK}.}]
478 task1 :: MTask v Int | mtask v
479 task1 = declarePin A3 PMInput \a3->{main=readA a3}
480
481 task2 :: MTask v Int | mtask v
482 task2 = declarePin D3 PMOutput \d3->{main=writeD d3 true}
483 \end{lstClean}
484
485 \subsection{Task combinators}
486 Task combinators are used to combine multiple tasks to describe workflows.
487 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.
488 There are three main types of task combinators, namely:
489 \begin{enumerate}
490 \item Sequential combinators that execute tasks one after the other, possibly using the result of the left hand side.
491 \item Parallel combinators that execute tasks at the same time combining the result.
492 \item Miscellaneous combinators that change the semantics of a task---e.g.\ repeat it or delay execution.
493 \end{enumerate}
494
495 \subsubsection{Sequential}
496 Sequential task combination allows the right-hand side expression to \emph{observe} the left-hand side task value.
497 All sequential task combinators are expressed in the \cleaninline{step} class and can be---and are by default---derived from the Swiss army knife step combinator \cleaninline{>>*.}.
498 This combinator has a single task on the left-hand side and a list of \emph{task continuations} on the right-hand side.
499 The list of task continuations is checked during evaluation of the left-hand side and if one of the predicates matches, the task continues with the result of this combination.
500 Several shorthand combinators are derived from the step combinator.
501 \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.
502 \cleaninline{>>\|.} is a shorthand for the sequence operation, if the left-hand side is stable, it continues with the right-hand side task.
503 The \cleaninline{>>~.} and \cleaninline{>>..} combinators are variants of the ones above that ignore the stability and continue on an unstable value as well.
504
505 \begin{lstClean}[label={lst:mtask_sequential},caption={Sequential task combinators in \gls{MTASK}.}]
506 class step v | expr v where
507 (>>*.) infixl 1 :: (MTask v t) [Step v t u] -> MTask v u
508 (>>=.) infixl 0 :: (MTask v t) ((v t) -> MTask v u) -> MTask v u
509 (>>|.) infixl 0 :: (MTask v t) (MTask v u) -> MTask v u
510 (>>~.) infixl 0 :: (MTask v t) ((v t) -> MTask v u) -> MTask v u
511 (>>..) infixl 0 :: (MTask v t) (MTask v u) -> MTask v u
512
513 :: Step v t u
514 = IfValue ((v t) -> v Bool) ((v t) -> MTask v u)
515 | IfStable ((v t) -> v Bool) ((v t) -> MTask v u)
516 | IfUnstable ((v t) -> v Bool) ((v t) -> MTask v u)
517 | Always (MTask v u)
518 \end{lstClean}
519
520 The following listing shows an example of a step in action.
521 The \cleaninline{readPinBin} function produces an \gls{MTASK} task that classifies the value of an analogue pin into four bins.
522 It also shows that the nature of embedding allows the host language to be used as a macro language.
523
524 \begin{lstClean}[label={lst:mtask_readpinbin},caption={Read an analogue pin and bin the value in \gls{MTASK}.}]
525 readPinBin :: Int -> Main (MTask v Int) | mtask v
526 readPinBin lim = declarePin PMInput A2 \a2->
527 { main = readA a2 >>*.
528 [ IfValue (\x->x <. lim) (\_->rtrn (lit bin))
529 \\ lim <-[64,128,192,256]
530 & bin <- [0..]]}
531 \end{lstClean}
532
533 \subsubsection{Parallel}\label{sssec:combinators_parallel}
534 The result of a parallel task combination is a compound task that actually results in both tasks being executed at the same time.
535 There are two types of parallel task combinators (see \cref{lst:mtask_parallel}).
536
537 \begin{lstClean}[label={lst:mtask_parallel},caption={Parallel task combinators in \gls{MTASK}.}]
538 class (.&&.) infixr 4 v :: (MTask v a) (MTask v b) -> MTask v (a, b)
539 class (.||.) infixr 3 v :: (MTask v a) (MTask v a) -> MTask v a
540 \end{lstClean}
541
542 The conjunction combinator (\cleaninline{.&&.}) combines the result by putting the values from both sides in a tuple.
543 The stability of the task depends on the stability of both children.
544 If both children are stable, the result is stable, otherwise the result is unstable.
545 The disjunction combinator (\cleaninline{.\|\|.}) combines the results by picking the leftmost, stablest task.
546 The semantics are most easily described using the \gls{CLEAN} functions shown in \cref{lst:semantics_con,lst:semantics_dis}.
547
548 \begin{figure}[ht]
549 \centering
550 \begin{subfigure}[t]{.5\textwidth}
551 \begin{lstClean}[caption={Semantics of the\\conjunction combinator.},label={lst:semantics_con}]
552 con :: (TaskValue a) (TaskValue b)
553 -> TaskValue (a, b)
554 con NoValue r = NoValue
555 con l NoValue = NoValue
556 con (Value l ls) (Value r rs)
557 = Value (l, r) (ls && rs)
558
559 \end{lstClean}
560 \end{subfigure}%
561 \begin{subfigure}[t]{.5\textwidth}
562 \begin{lstClean}[caption={Semantics of the\\disjunction combinator.},label={lst:semantics_dis}]
563 dis :: (TaskValue a) (TaskValue a)
564 -> TaskValue a
565 dis NoValue r = r
566 dis l NoValue = l
567 dis (Value l ls) (Value r rs)
568 | rs = Value r True
569 | otherwise = Value l ls
570 \end{lstClean}
571 \end{subfigure}
572 \end{figure}
573
574 \Cref{lst:mtask_parallel_example} gives an example program that uses the parallel task combinator.
575 This task read two pins at the same time, returning when one of the pins becomes high.
576 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 are high but not necessarily at the same time.
577
578 \begin{lstClean}[label={lst:mtask_parallel_example},caption={Parallel task combinator example in \gls{MTASK}.}]
579 task :: MTask v Bool
580 task =
581 declarePin D0 PMInput \d0->
582 declarePin D1 PMInput \d1->
583 let monitor pin = readD pin >>*. [IfValue (\x->x) \x->rtrn x]
584 In {main = monitor d0 .||. monitor d1}
585 \end{lstClean}
586
587 \subsubsection{Repeat}\label{sec:repeat}
588 In many workflows, tasks are to be executed continuously.
589 The \cleaninline{rpeat} combinator does this by executing the child task until it becomes stable.
590 Once a stable value is observed, the task is reinstated.
591 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}.
592
593 \begin{lstClean}[label={lst:mtask_repeat},caption={Repeat task combinators in \gls{MTASK}.}]
594 class rpeat v where
595 rpeat :: (MTask v a) -> MTask v a
596 \end{lstClean}
597
598 To demonstrate the combinator, \cref{lst:mtask_repeat_example} shows the \cleaninline{rpeat} combinator in use.
599 This resulting task mirrors the value read from analogue \gls{GPIO} pin \cleaninline{A1} to pin \cleaninline{A2} by constantly reading the pin and writing the result.
600
601 \begin{lstClean}[label={lst:mtask_repeat_example},caption={Repeat task combinator example in \gls{MTASK}.}]
602 task :: MTask v Int | mtask v
603 task =
604 declarePin A1 PMInput \a1->
605 declarePin A2 PMOutput \a2->
606 {main = rpeat (readA a1 >>~. writeA a2 >>|. delay (lit 1000))}
607 \end{lstClean}
608
609 \subsection{\texorpdfstring{\Glsxtrlongpl{SDS}}{Shared data sources}}
610 \todo[inline]{Explain \glspl{SDS} shortly.}
611 \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}).
612 Similar to peripherals (see \cref{sssec:peripherals}), they are constructed at the top level and are accessed through interaction tasks.
613 The \cleaninline{getSds} task yields the current value of the \gls{SDS} as an unstable value.
614 This behaviour is similar to the \cleaninline{watch} task in \gls{ITASK}.
615 Writing a new value to \pgls{SDS} is done using \cleaninline{setSds}.
616 This task yields the written value as a stable result after it is done writing.
617 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.
618 To circumvent this issue, \cleaninline{updSds} is available by which \pgls{SDS} can be atomacally updated.
619 The \cleaninline{updSds} task only guarantees atomicity within \gls{MTASK}.
620
621 \begin{lstClean}[label={lst:mtask_sds},caption={\Glspl{SDS} in \gls{MTASK}.}]
622 :: Sds a // abstract
623 class sds v where
624 sds :: ((v (Sds t)) -> In t (Main (MTask v u))) -> Main (MTask v u)
625 getSds :: (v (Sds t)) -> MTask v t
626 setSds :: (v (Sds t)) (v t) -> MTask v t
627 updSds :: (v (Sds t)) ((v t) -> v t) -> MTask v t
628 \end{lstClean}
629
630 \Cref{lst:mtask_sds_examples} shows an example task that uses \glspl{SDS}.
631 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}.
632 In the \cleaninline{main} expression, this function is called twice and the results are combined using the parallel or combinator (\cleaninline{.\|\|.}).
633 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}
634
635 \begin{lstClean}[label={lst:mtask_sds_examples},caption={Examples with \glspl{SDS} in \gls{MTASK}.}]
636 task :: MTask v Int | mtask v
637 task = declarePin D3 PMInput \d3->
638 declarePin D5 PMInput \d5->
639 sds \share=0
640 In fun \count=(\pin->
641 readD pin
642 >>* [IfValue (\x->x) (\_->updSds (\x->x +. lit 1) share)]
643 >>| delay (lit 100) // debounce
644 >>| count pin)
645 In {main=count d3 .||. count d5}
646 \end{lstClean}
647
648 \section{Conclusion}
649 The \gls{MTASK} language is a rich \gls{TOP} language tailored for \gls{IOT} edge devices.
650 It is embedded in the pure functional language \gls{CLEAN} and uses an enriched lambda calculus as a host language.
651 It provides support for all common arithmetic expressions, conditionals, functions, but also several basic tasks, task combinators, peripheral support and integration with \gls{ITASK}.
652 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.
653 As a result, a single declarative specification can describe an entire \gls{IOT} system.
654 \todo[inline]{Uitbreiden?}
655
656 \input{subfilepostamble}
657 \end{document}