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