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