kill all orphans and widows
authorMart Lubbers <mart@martlubbers.net>
Wed, 8 Mar 2023 19:45:45 +0000 (20:45 +0100)
committerMart Lubbers <mart@martlubbers.net>
Wed, 8 Mar 2023 19:45:45 +0000 (20:45 +0100)
14 files changed:
appx/c4hp.tex
appx/mtask_aux.tex
back/summary.tex
bib/other.bib
bib/self.bib
bib/tiot.bib
preamble/listings.tex
thesis.tex
top/finale.tex
top/green.tex
top/imp.tex
top/int.tex
top/lst/example.icl
tvt/tvt.tex

index c610e92..abde24f 100644 (file)
@@ -68,7 +68,7 @@ f :: v:a u:b -> u:b, [v<=u]  // f works when a is less unique than b
 \subsection{Expressions}
 Patterns in \gls{CLEAN} can be used as predicates as well \citep[\citesection{3.4.3}]{plasmeijer_clean_2021}.
 Using the \cleaninline{=:} operator, a value is tested against a pattern.
-Variable names are not allowed but wildcard patterns \cleaninline{\_} are.
+Variable names are not allowed but wildcard patterns (\cleaninline{\_}) are.
 
 \begin{lstClean}[label={lst:matches_pattern_expression},caption={Examples of \emph{matches pattern} expressions.}]
 isNil :: [a] -> Bool
index a088aa0..fffec62 100644 (file)
@@ -133,7 +133,11 @@ class LEDMatrix v where
 \end{lstClean}
 
 \subsection{Connection types}\label{lst:connection_types}
-\begin{lstClean}[caption={}]
+The connection between the \gls{ITASK} server and the \gls{MTASK} devices are communication method agnostic.
+As long as the \cleaninline{channelSync} type class is implemented, the communication method can be used.
+\Cref{lst:conn_types} shows the data types for the connections.
+
+\begin{lstClean}[label={lst:conn_types},caption={Data types for the different connections in \gls{MTASK}.}]
 :: TCPSettings =
        { host        :: String
        , port        :: Int
@@ -157,7 +161,6 @@ class LEDMatrix v where
        }
 \end{lstClean}
 
-
 \lstset{basicstyle=\tt}
 \input{subfilepostamble}
 \end{document}
index c31412d..41272cb 100644 (file)
@@ -7,12 +7,11 @@
 \ifSubfilesClassLoaded{\chapter*{Summary}}{\chapter{Summary}}%
 \label{chp:summary}%
 \glsresetall%
-Programming \gls{IOT} systems is complex since they are dynamic, interactive, distributed, collaborative, multi-tiered, and multitasking in nature.
+The development of reliable software for the \gls{IOT} is difficult because \gls{IOT} systems are dynamic, interactive, distributed, collaborative, multi-tiered, and multitasking in nature.
 The complexity is increased further by semantic friction that arises through different hardware and software characteristics between tiers.
 Many computers that operate in \gls{IOT} systems are \emph{edge devices} that interact with the environment using sensors and actuators.
-Edge devices often use low-cost microcontrollers designed for embedded applications.
+Edge devices are often powered by low-cost microcontrollers designed for embedded applications.
 They have little memory, unhurried processors, and are slow in communication but are also small and energy efficient.
-%Hence they require additional care.
 
 \Gls{TOP} can cope with the challenges of \gls{IOT} programming.
 In \gls{TOP}, the main building blocks are tasks, an abstract representation of work.
index b2fcf59..bdf11a6 100644 (file)
@@ -412,7 +412,7 @@ Publisher: {ACM}},
 @thesis{serrano_type_2018,
        title = {Type Error Customization for Embedded Domain-Specific Languages},
        institution = {Utrecht University},
-       type = {phdthesis},
+       type = {PhD Thesis},
        author = {Serrano, Alejandro},
        date = {2018},
 }
index f2a3b96..0ae5b7e 100644 (file)
@@ -11,7 +11,7 @@
        publisher = {{ACM}},
        author = {Lubbers, Mart and Koopman, Pieter and Plasmeijer, Rinus},
        editor = {Stutterheim, JurriĆ«n and Chin, Wei Ngan},
-       date = {2019},
+       date = {2021},
        note = {event-place: Singapore, Singapore},
        keywords = {clean, distributed applications, functional programming, internet of things, task oriented programming},
        file = {Lubbers et al. - 2019 - Interpreting Task Oriented Programs on Tiny Comput.pdf:/home/mrl/.local/share/zotero/storage/ATYSJXJ3/Lubbers et al. - 2019 - Interpreting Task Oriented Programs on Tiny Comput.pdf:application/pdf},
 @inproceedings{lubbers_first-class_2022,
        location = {New York, {NY}, {USA}},
        title = {First-Class Data Types in Shallow Embedded Domain-Specific Languages using Metaprogramming},
+       isbn = {978-1-4503-9831-2},
+       doi = {10.1145/3587216.3587219},
        series = {{IFL} '22},
        eventtitle = {Symposium on Implementation and Application of Functional Languages},
        booktitle = {Proceedings of the 34st Symposium on Implementation and Application of Functional Languages},
        publisher = {{ACM}},
        author = {Lubbers, Mart and Koopman, Pieter and Plasmeijer, Rinus},
-       date = {2022},
-       note = {event-place: Kopenhagen, Denmark. in-press},
+       date = {2023},
+       numpages = {12},
+       note = {event-place: Copenhagen, Denmark. in-press},
        keywords = {clean, distributed applications, functional programming, internet of things, task oriented programming},
 }
-
 @book{lubbers_orchestrating_2023,
        location = {Nijmegen},
        title = {Orchestrating the Internet of Things using Task-Oriented Programming},
index c0d034c..241993c 100644 (file)
 }
 
 @Misc{           wiki:io,
-  author       = "HaskellWiki",
+  author       = {{HaskellWiki contributors}},
   title                = "Introduction to IO --- HaskellWiki{,} ",
   year         = "2020",
   url          = "https://wiki.haskell.org/index.php?title=Introduction_to_IO&oldid=63493",
index e975b3d..49715c2 100644 (file)
@@ -96,6 +96,7 @@
 \usepackage[algochapter,linesnumbered,lined,boxed]{algorithm2e}
 % Fix the algorithm font
 \renewcommand\AlCapFnt{\normalfont}
+\setlength{\AlCapSkip}{1ex}
 
 \makeatletter
 \patchcmd{\lsthk@SelectCharTable}{%
index d0fcd9b..d25e935 100644 (file)
 %\setlength{\overfullrule}{20pt}
 
 % Just for the todonotes, can go when it's finished
-\usepackage{todonotes}
-\setuptodonotes{
-       backgroundcolor=white,
-       linecolor=black,
-%      size=tiny,
-}
+%\usepackage{todonotes}
+%\setuptodonotes{
+%      backgroundcolor=white,
+%      linecolor=black,
+%}
 
 % Document info
 \title{\mytitle\texorpdfstring{\\[2ex]}{---}\smaller\mysubtitle}
index 0d1018e..1b65cfc 100644 (file)
@@ -24,8 +24,8 @@ Every layer has its own software and hardware characteristics, resulting in sema
 It is hard to orchestrate the smooth cooperation of the individual components, especially during maintenance of the entire \gls{IOT} application.
 \Gls{TOP} is a declarative programming paradigm designed to describe multi-tiered interactive systems from a single source.
 Such a tierless system prevents the orchestration problems of the tiered approach.
+The type system of the host language checks the \gls{ITASK} and \gls{MTASK} components and their interaction.
 However, it is not straightforward to run \gls{TOP} systems on resource-constrained devices such as edge devices.
-The type system of the host language checks the \gls{ITASK} and \gls{MTASK} components as well as their interaction.
 
 The \gls{MTASK} system bridges this gap by providing a \gls{TOP} programming language for edge devices.
 It is a full-fledged \gls{TOP} language hosted in a tiny \gls{FP} language.
@@ -33,7 +33,7 @@ Besides the usual \gls{FP} constructs, it contains basic tasks, task combinators
 It integrates seamlessly in \gls{ITASK}, a \gls{TOP} system for interactive web applications.
 In \gls{ITASK}, abstractions are available for the gritty details of interactive web applications such as program distribution, web applications, data storage, and user management.
 The \gls{MTASK} system abstracts away of all technicalities specific to edge devices such as communication, abstractions for sensors and actuators, interrupts and (multi) task scheduling.
-With \gls{ITASK} and \gls{MTASK}, all layers of an \gls{IOT} system can be programmed from a single declarative specification.
+When \gls{MTASK} is used together with \gls{MTASK}, all layers of the \gls{IOT} application are programmed from a single declarative specification.
 
 Any device equipped with the \gls{MTASK} \gls{RTS} can be used in the system and dynamically receive tasks for execution.
 This domain-specific \gls{OS} only is uploaded once, hence saving precious write cycles on the program memory.
@@ -46,7 +46,7 @@ Furthermore, \gls{ITASK} \glspl{SDS} can be lowered to \gls{MTASK} tasks as well
 \section{Related work}
 The novelties of the \gls{MTASK} system can be compared to existing systems in several categories.
 It is an interpreted (\cref{sec:related_int}) \gls{TOP} (\cref{sec:related_top}) \gls{DSL} (\cref{sec:related_dsl}) that may seem similar at first glance to \gls{FRP} (\cref{sec:related_frp}), it is implemented in a functional language (\cref{sec:related_fp}) and due to the execution semantics, multitasking is automatically supported (\cref{sec:related_multi}).
-\Cref{sec_t4t:TiredvsTierless} contains an elaborate related work section regarding tierless systems in general.
+\Cref{sec_t4t:TiredvsTierless} contains an elaborate related work section regarding tierless systems.
 
 \subsection{Interpretation}\label{sec:related_int}
 There are a myriad of interpreted programming languages available for more powerful edge devices.
@@ -56,12 +56,12 @@ They lay pretty hefty constraints on the memory and as a result do not work on s
 Another interpretation solution for the tiniest devices is Firmata, a protocol for remotely controlling the microcontroller using a server as the interpreter host \citep{steiner_firmata:_2009}.
 \citet{grebe_haskino:_2016} wrapped this in a remote monad for integration with \gls{HASKELL} that allowed imperative code to be interpreted on the microprocessors.
 Later this system was extended to support multithreading as well, stepping away from Firmata as the basis and using their own \gls{RTS} \citep{grebe_threading_2019}.
-It differs from our approach because continuation points need to be defined by hand there is no automatic safe data communication.
+It differs from our approach because it is required to mark continuation points by hand and there is no automatic safe data communication.
 
 \Citet{baccelli_reprogramming_2018} provide a single language \gls{IOT} system based on the RIOT \gls{OS} that allows runtime deployment of code snippets called containers.
 Both client and server are written in JavaScript.
 However, there is no integration between the client and the server other than that they are programmed from a single source.
-Mat\`e is an example of an early tierless sensor network framework where devices are provided with a virtual machine using TinyOS for dynamic provisioning \citep{levis_mate_2002}.
+Mat\`e is an example of a tierless framework for sensor networks where devices run a virtual machine using TinyOS for dynamic provisioning \citep{levis_mate_2002}.
 
 \subsection{DSLs}\label{sec:related_dsl}
 Many \glspl{DSL} provide higher-level programming abstractions for microcontrollers, for example providing strong typing or memory safety.
@@ -90,13 +90,13 @@ This results in hard to maintain, error-prone and unscalable spaghetti code.
 There are many solutions to overcome this problem in imperative languages.
 If the host language is a functional language (e.g.\ the aforementioned scheme variants) multitasking can be achieved without this burden relatively easy using continuation style multiprocessing \citep{wand_continuation-based_1980}.
 Writing in this style is complicated and converting an existing program in this continuation passing style results in relatively large programs.
-Furthermore, there is no built-in thread-safe communication possible between the tasks.
-A \gls{TOP} or \gls{FRP} based language is superior to manual threading because the programmer is not required to explicitly define continuation points.
+Moreover, there is no built-in thread-safe communication possible between the tasks.
+A \gls{TOP} or \gls{FRP} language is superior to manual threading because the programmer is not required to explicitly define continuation points.
 
 Regular preemptive multithreading is too memory intensive for smaller microcontrollers and therefore not suitable.
 Manual interleaving of imperative code can be automated to certain extents.
-Solutions often require an \gls{RTOS}, have a high memory requirement, do not support local variables, no thread-safe shared memory, no composition or no events as described in \cref{tbl:multithreadingcompare}.
-This table extends a comparison table with various solutions to multitasking to \gls{MTASK} in the relevant categories.
+Solutions often require an \gls{RTOS}, have a high memory requirement, do not support local variables, no thread-safe shared memory, no composition, or no events as described in \cref{tbl:multithreadingcompare}.
+This table extends the comparison table with \gls{MTASK} in the relevant categories.
 
 \begin{table}
        \begin{threeparttable}
@@ -146,19 +146,16 @@ Tasks in \gls{TOP} are also event driven and can be combined with combinators.
 \Gls{TOP} allows for more complex collaboration patterns than \gls{FRP} \citep{wang_maintaining_2018}.
 Consequently, \gls{TOP} is unable to provide strong guarantees on memory usage, something \gls{FRP} is capable of.
 For example, arrowised \gls{FRP} can give guarantees on upper memory bounds \citep{nilsson_functional_2002}.
-
 The way \gls{FRP}, and for that matter \gls{TOP}, systems are programmed stays close to the design when the domain matches suits the paradigm.
 The \gls{IOT} domain seems to suit this style of programming very well in just the device layer but also for entire \gls{IOT} systems.
 
 For example, Potato is an \gls{FRP} language for building entire \gls{IOT} systems using powerful devices such as the Raspberry Pi leveraging the Erlang \gls{VM} \citep{troyer_building_2018}.
 It requires client devices to be able to run the Erlang \gls{VM} which makes it unsuitable for low memory environments.
-
 The emfrp language compiles a \gls{FRP} specification for a microcontroller to \gls{C} code \citep{sawada_emfrp:_2016}.
 The \gls{IO} part, the bodies of some functions, still need to be implemented.
 These \gls{IO} functions can then be used as signals and combined as in any \gls{FRP} language.
 Due to the compilation to \gls{C} it is possible to run emfrp programs on tiny computers.
 However, in contrast to in \gls{MTASK}, the tasks are not interpreted and there is no automated communication with a server.
-
 Other examples are CFRP \citep{suzuki_cfrp_2017}, XFRP \citep{shibanai_distributed_2018}, Juniper \citep{helbling_juniper:_2016}, Hailstorm \citep{sarkar_hailstorm_2020}, Haski \citep{valliappan_towards_2020}, arduino-copilot \citep{hess_arduino-copilot_2020}.
 
 \subsection{Task-oriented programming}\label{sec:related_top}
@@ -186,7 +183,8 @@ Nonetheless, this deserves much more attention.
 The future and related work for the security of \gls{MTASK} and tierless systems is more thoroughly presented in \cref{ssec_t4t:security}.
 
 \subsection{Advanced edge devices techniques}
-Edge devices produce a lot of data and it is not always effective to send this data to the server for processing.
+Edge devices produce a lot of data.
+It is not always effective to send this data to the server for processing.
 Leaving the produced data and computations on the edge device is called edge computing \citep{shi_edge_2016}.
 The \gls{MTASK} system exhibits many properties of edge computing because it is possible to run entire workflows on the device.
 However, it is interesting to see how far this can be extended.
@@ -204,14 +202,15 @@ These blocks are marked as such, because in the case of a reset of the system, t
 Examples of such blocks are \gls{I2C} transmissions or calculations that rely on recent sensor data.
 In \gls{MTASK}, all work expressed by tasks is already split up in atomic pieces of work, i.e.\ the work is a side effect of rewriting.
 Furthermore, creating checkpoints is fairly straightforward as \gls{MTASK} tasks do not rely on any global state---all information required to execute a task is stored in the task tree.
-It is interesting to see what \gls{TOP} abstraction are useful for intermittent computing and what solutions are required to make this work.
+It is interesting to see what \gls{TOP} abstractions are useful to support intermittent computing properly and what solutions are required to make it work.
 
 Mesh networks allow for communication not only to and fro the device and server but also between devices.
 The \gls{ITASK} system already contains primitives for distributed operation.
 For example, it is possible to run tasks or share data with \glspl{SDS} on different machines.
 It is interesting to investigate how this networking technique can be utilised in \gls{MTASK}.
 
-\Glspl{FPGA} have been becoming cheaper and faster recently, allowing for purely functional code to be translated to \glspl{FPGA} code efficiently \citep{baaij_digital_2015}.
+\Glspl{FPGA} are highly customisable integrated chips consisting of programmable gates.
+Promising research has gone into translating purely functional code to \gls{FPGA} configurations \citep{baaij_digital_2015}.
 It would be interesting to see how and whether (parts of) \gls{TOP} programs or the functionality of the \gls{MTASK} \gls{OS} could be translated to \gls{FPGA} specifications.
 
 \subsection{Formal semantics}
@@ -233,7 +232,7 @@ However, this approach requires a very powerful host language in which task comb
 It could be fruitful to investigate which workflows cannot be specified with the limited set of combinators available in \gls{MTASK}.
 Furthermore, it is unclear whether all derived combinators from \gls{ITASK} can be expressed in terms of \gls{MTASK} combinators.
 \Citet{van_der_aalst_workflow_2003} defines a benchmark set of workflow patterns.
-It is interesting to see which patterns can be implemented with \gls{MTASK}, and what additional combinators are needed.
+It is interesting to see which patterns can already be implemented with just \gls{MTASK}, which require a round-trip with the server, and what additional combinators would be needed.
 
 Editors are a crucial part of \gls{TOP}.
 In \gls{MTASK}, sensors can be seen as read-only shared editors that are updated by the system.
index e86f0b2..132d9e9 100644 (file)
@@ -404,7 +404,7 @@ Next, the microcontroller goes to light sleep for the minimum of a predefined in
 In general, the microcontroller executes multiple \gls{MTASK} tasks at the same time.
 The \gls{MTASK} device repeatedly check for inputs from the server and executes all tasks that cannot be delayed to the next evaluation round one step.
 The tasks are stored in a priority queue to check efficiently which of them need to be stepped.
-The \gls{MTASK} tasks are ordered at their absolute latest start time in this queue; earliest deadline first.
+The \gls{MTASK} tasks are ordered at their latest start time in this queue; earliest deadline first.
 We use the earliest deadline to order tasks with equal latest deadline.
 
 It is very complicated to make an optimal scheduling algorithm for tasks to minimise the energy consumption.
@@ -487,7 +487,7 @@ There are several different types of interrupts possible that each fire in sligh
 The example shows a debounced light switch for the built-in \gls{LED} connected to \gls{GPIO} pin 13.
 When the user presses the button connected to \gls{GPIO} pin 11, the state of the \gls{LED} changes.
 As buttons sometimes induce noise shortly after pressing, events within \qty{30}{\ms} after pressing are ignored.
-In between the button presses, the device goes into deep sleep using the \arduinoinline{LowPower} library.
+In between the button presses, the device goes into deep sleep using the \arduinoinline{LowPower} library to handle the processor specific sleep interface.
 
 \Crefrange{lst:arduino_interrupt:defs_fro}{lst:arduino_interrupt:defs_to} defines the pin and debounce constants.
 \Cref{lst:arduino_interrupt:state} defines the current state of the \gls{LED}, it is declared \arduinoinline{volatile} to exempt it from compiler optimisations because it is accessed in the interrupt handler.
@@ -534,6 +534,9 @@ void buttonPressed() { /* ISR */ [+\label{lst:arduino_interrupt:isr_fro}+]
 \Cref{lst:mtask_interrupts} shows the interrupt interface in \gls{MTASK}.
 The \cleaninline{interrupt} class contains a single function that, given an interrupt mode and a \gls{GPIO} pin, produces a task that represents this interrupt.
 Lowercase variants of the various interrupt modes such as \cleaninline{change :== lit Change} are available as convenience macros (see \cref{sec:expressions}).
+When the \gls{MTASK} device executes this task, it installs an \gls{ISR} and sets the rewrite rate of the task to infinity, $\rewriterate{\infty}{\infty}$.
+The interrupt handler is set up in such a way that the rewrite rate is changed to $\rewriterate{0}{0}$ once the interrupt triggers.
+As a consequence, the task is executed on the next execution cycle.
 
 \begin{lstClean}[label={lst:mtask_interrupts},caption={The interrupt interface in \gls{MTASK}.}]
 class interrupt v where
@@ -542,10 +545,6 @@ class interrupt v where
 :: InterruptMode = Change | Rising | Falling | Low | High
 \end{lstClean}
 
-When the \gls{MTASK} device executes this task, it installs an \gls{ISR} and sets the rewrite rate of the task to infinity, $\rewriterate{\infty}{\infty}$.
-The interrupt handler is set up in such a way that the rewrite rate is changed to $\rewriterate{0}{0}$ once the interrupt triggers.
-As a consequence, the task is executed on the next execution cycle.
-
 The \cleaninline{pirSwitch} function in \cref{lst:pirSwitch} creates, given an interval in milliseconds, a task that reacts to motion detection by a \gls{PIR} sensor (connected to \gls{GPIO} pin 0) by lighting the \gls{LED} connected to \gls{GPIO} pin 13 for the given interval.
 The system turns on the \gls{LED} again when there is still motion detected after this interval.
 By changing the interrupt mode in this program text from \cleaninline{high} to \cleaninline{rising} the system lights the \gls{LED} only one interval when it detects motion, no matter how long this signal is present at the \gls{PIR} pin.
index c8ff4f4..39a6347 100644 (file)
@@ -47,30 +47,16 @@ The design, architecture and implementation of the \gls{RTS} is shown in \cref{s
 \end{figure}
 
 \section{Compiler}\label{sec:compiler_imp}
-%The byte code compiler for \gls{MTASK} is an interpretation of the \gls{MTASK} language.
-%In order to compile terms, instances for all \gls{MTASK} type classes are required for the \cleaninline{:: BCInterpret a} type.
-%Terms in \gls{MTASK} are constructed and compiled at run time but type checked at compile time in the host language \gls{CLEAN}.
-%The compiled tasks are sent to the device for interpretation, a detailed overview of the execution process is found in \cref{sec:compiler_rts}.
-%The result of compilation is the byte code, and some metadata regarding the used peripherals and \glspl{SDS}.
-%Interpreting the byte code only uses the stack, hence, all data types are unboxed.
-%
-%The heap is only used to store the task trees that 
-%
-%The byte code is interpreted by the interpreter 
-%In order to make it work on resource-constrained microcontrollers, some properties of the language are strictly enforced.
-%is designed to generate code that runs on resource-constrained edge devices.
-%There is no heap avaliable for expressions, only for tasks
-\todo[inline]{Zou je hier niet een prargraafje schrijven over dat dit een beetje speciale compiler is.  Alle type checks worden al door Clean gedaan. Dat is voordat deze compiler ooit uitgevoerd gaat worden. Bovendien kan het Clean programma de te compileren byte code dynamisch maken. Dat staat natuurlijk al eerder een keer, maar je make niet aannemen dat iedereen alles leest (en nu nog weet)
-Dit gaat wel hard de diepte in.  Zou je niet een kort stukje schrijven over hoe je bytecode machine er uit ziet?
-       Heap: voor de huidige task tree die herschreven wordt.
-       Function code: sequence of bytecode instructie.
-       SDSs + Objects
-       Stack om expressies te evelaueren en function calls te doen.
-       Plaatje a la Figure 7.5. 
-
-       Om de code te maken heb je een intsantie van alle classen in mTask nodig voor BCInterpret a.
-
-Voor veel lezers zou het genoeg zijn om alleen dat te snappen, maak het ze eenvoudig.}
+The byte code compiler for \gls{MTASK} is an interpretation of the \gls{MTASK} language.
+In order to compile terms, instances for all \gls{MTASK} type classes are required for the \cleaninline{:: BCInterpret a} type.
+Terms in \gls{MTASK} are constructed and compiled at run time, but type checked at compile time in the host language \gls{CLEAN}.
+The compiled tasks are sent to the device for interpretation.
+The result of the compilation is the byte code and some metadata regarding the used peripherals and \glspl{SDS}.
+The compilation target is the interpreter of the \gls{MTASK} \gls{RTS}.
+In order to keep the hardware requirements down, all expressions are evaluated on a stack.
+Rewriting of tasks uses the same stack and also a heap.
+The heap usage is minimised by applying aggressive memory management.
+A detailed overview of the \gls{RTS} including the interpreter and rewriter is found in \cref{sec:compiler_rts}.
 
 \subsection{Compiler infrastructure}
 The byte code compiler interpretation for the \gls{MTASK} language is implemented as a monad stack containing a writer monad and a state monad.
@@ -183,15 +169,14 @@ More information is given in the schemes requiring such arguments.
 
 \begin{table}
        \centering
-       \caption{An overview of the compilation schemes.}
+       \caption{An overview of the compilation rules.}
        \begin{tabularx}{\linewidth}{l X}
                \toprule
                Scheme & Description\\
                \midrule
-               $\cschemeE{e}{r}$ & Produces the value of expression $e$ given the context $r$ and pushes it on the stack.
-                       The result can be a basic value or a pointer to a task.\\
-               $\cschemeF{e}$ & Generates the bytecode for functions.\\
-               $\cschemeS{e}{r}{w} $ & Generates the function for the step continuation given the context $r$ and the width $w$ of the left-hand side task value.\\
+               $\cschemeE{e}{r}$ & Generates code for expressions given the context $r$\\
+               $\cschemeF{e}$ & Generates the code for functions.\\
+               $\cschemeS{e}{r}{w} $ & Generates the code for the step continuations given the context $r$ and the width $w$ of the left-hand side task value.\\
                \bottomrule
        \end{tabularx}
 \end{table}
@@ -202,6 +187,8 @@ The argument of $\mathcal{E}$ is the context (see \cref{ssec:functions}).
 Values are always placed on the stack; tuples and other compound data types are unpacked.
 Function calls, function arguments and tasks are also compiled using $\mathcal{E}$ but their compilations is explained later.
 
+\begingroup
+\allowdisplaybreaks%
 \begin{align*}
        \cschemeE{\text{\cleaninline{lit}}~e}{r} & = \text{\cleaninline{BCPush (bytecode e)}};\\
        \cschemeE{e_1\mathbin{\text{\cleaninline{+.}}}e_2}{r} & = \cschemeE{e_1}{r};
@@ -233,6 +220,7 @@ Function calls, function arguments and tasks are also compiled using $\mathcal{E
                {} & \text{\emph{Where $w_l$ is the width of the left and, $w_r$ of the right value}}\\
                {} & \text{\emph{similar for other unboxed compound data types}}\\
 \end{align*}
+\endgroup
 
 Translating $\mathcal{E}$ to \gls{CLEAN} code is very straightforward, it basically means writing the instructions to the writer monad.
 Almost always, the type of the interpretation is not used, i.e.\ it is a phantom type.
@@ -347,6 +335,8 @@ Task trees are created with the \cleaninline{BCMkTask} instruction that allocate
 It pops arguments from the stack according to the given task type.
 The following extension of $\mathcal{E}$ shows this compilation scheme (except for the step combinator, explained in \cref{ssec:step}).
 
+\begingroup
+\allowdisplaybreaks%
 \begin{align*}
        \cschemeE{\text{\cleaninline{rtrn}}~e}{r} & =
                        \cschemeE{e}{r};
@@ -383,13 +373,14 @@ The following extension of $\mathcal{E}$ shows this compilation scheme (except f
                        \cschemeE{e_2}{r};
                        \text{\cleaninline{BCMkTask BCAnd}};\\
 \end{align*}
+\endgroup%
 
-This translates to Clean code by writing the correct \cleaninline{BCMkTask} instruction as exemplified in \cref{lst:imp_ret}.
+This compilation scheme translates to Clean code by first writing the arguments and then the correct \cleaninline{BCMkTask} instruction.
+This is shown for the \cleaninline{.&&.} task in \cref{lst:imp_ret}.
 
 \begin{lstClean}[caption={The byte code interpretation implementation for \cleaninline{rtrn}.},label={lst:imp_ret}]
-instance rtrn BCInterpret
-where
-       rtrn m = m >>| tell` [BCMkTask (bcstable m)]
+instance .&&. BCInterpret where
+       (.&&.) l r = l >>| r >>| tell` [BCMkTask BCTAnd]
 \end{lstClean}
 
 \subsection{Sequential combinator}\label{ssec:step}
@@ -478,8 +469,7 @@ instance step BCInterpret where
                                //Return width (always 1, a task pointer)
                                (Just one)
                >>| modify (\s->{s & bcs_context=ctx})
-               >>| tell` [BCMkTask (instr rhswidth funlab)]
-
+               >>| tell` [BCMkTask (instr rhswidth funlab)][+\pagebreak+]
 toContFun :: JumpLabel UInt8 -> BCInterpret a
 toContFun steplabel contextwidth
        = foldr tcf (tell` [BCPush fail]) cont
@@ -500,23 +490,20 @@ The \glspl{SDS} are typed as functions in the host language, so an argument for
 For this, an \cleaninline{BCInterpret} is created that emits this identifier.
 When passing it to the function, the initial value of the \gls{SDS} is returned.
 In the case of a local \gls{SDS}, this initial value is stored as a byte code encoded value in the state and the compiler continues with the rest of the program.
-
-\begin{align*}
-       \cschemeF{\text{\cleaninline{sds}}~x=i~\text{\cleaninline{In}}~m} & =
-               \cschemeF{m};\\
-\end{align*}
-
 The \gls{SDS} access tasks have a compilation scheme similar to other tasks (see \cref{ssec:scheme_tasks}).
 The \cleaninline{getSds} task just pushes a task tree node with the \gls{SDS} identifier embedded.
 The \cleaninline{setSds} task evaluates the value, lifts that value to a task tree node and creates \pgls{SDS} set node.
 
 \begin{align*}
+       \cschemeF{\text{\cleaninline{sds}}~x=i~\text{\cleaninline{In}}~m} & =
+               \cschemeF{m};\\
+       \\
        \cschemeE{\text{\cleaninline{getSds}}~s}{r} & =
-               \text{\cleaninline{BCMkTask}} (\text{\cleaninline{BCSdsGet}} s);\\
+               \text{\cleaninline{BCMkTask}}~(\text{\cleaninline{BCSdsGet}}~s);\\
        \cschemeE{\text{\cleaninline{setSds}}~s~e}{r} & =
                \cschemeE{e}{r};
                \text{\cleaninline{BCMkTask BCStable}}_{\stacksize{e}};\\
-       {} & \mathbin{\phantom{=}} \text{\cleaninline{BCMkTask}} (\text{\cleaninline{BCSdsSet}} s);\\
+       {} & \mathbin{\phantom{=}} \text{\cleaninline{BCMkTask}}~(\text{\cleaninline{BCSdsSet}}~s);\\
 \end{align*}
 
 \Cref{lst:comp_sds} shows the implementation of the \cleaninline{sds} type class.
index c4911e0..20df4f8 100644 (file)
@@ -224,7 +224,7 @@ To lower the bandwidth, tasks can also be preloaded.
 Furthermore, the \gls{MTASK} tasks interact with \gls{ITASK} \glspl{SDS} using the \cleaninline{lowerSds} construct.
 All of this together allows programming all layers of an \gls{IOT} system from a single source and in a single paradigm.
 All details regarding interoperation are automatically taken care of.
-The following section contains an elaborate example using all integration functions that has deliberately been placed after the conclusion.
+The following section contains an elaborate example using all integration functions that has deliberately been placed after the conclusion for formatting reasons.
 
 \newpage
 \vspace*{\fill}
@@ -236,14 +236,16 @@ The following section contains an elaborate example using all integration functi
 \newpage
 
 \section{Home automation}
-This section presents an interactive home automation program (\cref{lst:example_home_automation}) to illustrate the integration of the \gls{MTASK} language and the \gls{ITASK} system.\todo{Meer uitleg over de applicatie? lijst ipv strings voor keuze?}
-It consists of a web interface for the user to control which tasks are executed on either one of two connected devices: an \gls{ARDUINO} UNO, connected via a serial port; and an ESP8266 based prototyping board called NodeMCU, connected via \gls{TCP}\slash{}\gls{WIFI}.
+This section presents an interactive home automation program (\cref{lst:example_home_automation}) to illustrate the dynamic integration of the \gls{MTASK} language and the \gls{ITASK} system.
+All layers of \gls{IOT} systems are used in this application.
+The presentation layer consists of an automatically generated web interface for the user to control which tasks sent to a device for execution.
+The application layer is the \gls{ITASK} server, the coordinator of the tasks in the system that also stores the data.
+The perception layer is populated by two devices: an \gls{ARDUINO} UNO, and an ESP8266 based prototyping board called {NodeMCU}.
 \Crefrange{lst:example:spec1}{lst:example:spec2} show the specification for the devices.
 The UNO is connected via serial using the UNIX filepath \path{/dev/ttyACM0} and the default serial port settings.
-The NodeMCU is connected via \gls{WIFI} and hence the \cleaninline{TCPSettings} record is used.
-%Both types have \cleaninline{channelSync} instances.
+The NodeMCU is connected via \gls{TCP} over \gls{WIFI} and hence the \cleaninline{TCPSettings} record is used.
 
-The code consists of an \gls{ITASK} part and several \gls{MTASK} parts.
+The code is split up into an \gls{ITASK} part and several \gls{MTASK} parts.
 \Crefrange{lst:example:task1}{lst:example:task2} contains the \gls{ITASK} task that coordinates the \gls{IOT} application.
 First the devices are connected (\crefrange{lst:example:conn1}{lst:example:conn2}) followed by launching a \cleaninline{parallel} task, visualised as a tabbed window, and a shutdown button to terminate the program (\crefrange{lst:example:par1}{lst:example:par2}).
 This parallel task is the controller of the tasks that run on the edge devices.
@@ -254,27 +256,30 @@ The interface that is generated for this is seen in \cref{fig:example_screenshot
 After selecting the task, a device is selected (see \cref{fig:example_screenshots2,lst:example:selectdev}).
 When both a task and a device are selected, an \gls{ITASK} task is added to the process list using \cleaninline{appendTask}.
 Using the helper function \cleaninline{mkTask}, the actual task is selected from the \cleaninline{tasks} list and executed by providing it the device argument.
-For example, when selecting the \cleaninline{temperature} task, the current temperature is shown to the user (\cref{fig:example_screenshots3}).
+
+The \cleaninline{tasks} list contains named \gls{MTASK} tasks that can be sent to the device.
+When selecting the \cleaninline{temperature} task, the current temperature is shown to the user (\cref{fig:example_screenshots3}).
 This task just sends a simple temperature monitoring task to the device using \cleaninline{liftmTask} and provides a view on its task value using the \cleaninline{>\&>} \gls{ITASK} combinator.
 This combinator allows the observation of the left-hand side task's value through \pgls{SDS}.
 The light switch task at \crefrange{lst:example:ls1}{lst:example:ls2} is a task that has bidirectional interaction using the definition of \cleaninline{lightswitch} shown in \cref{lst:mtask_liftsds_ex}.
-Using \cleaninline{lowerSds}, the status of the light switch is synchronised with the user.
-Finally, a task that calculates the factorial of a user-provided number is shown in the list.
+Using \cleaninline{lowerSds}, the server-side status of the light switch is synchronised with the actual light attached to the \gls{GPIO} pin.
+Finally, some tasks contain significant \gls{ITASK} portions as well.
+The remote computation task first queries the user for a number and then constructs a tailor-made task to send to the device to perform a computation, i.e.\ it calculates the factorial for the given number.
 
-\begin{figure}[!ht]
+\begin{figure}[p]
        \centering
-       \begin{subfigure}[b]{.3\linewidth}
-               \includegraphics[width=\linewidth]{home_auto1}
+       \begin{subfigure}{.33\linewidth}
+               \includegraphics[width=.9\linewidth]{home_auto1}
                \caption{Select task.}%
                \label{fig:example_screenshots1}
-       \end{subfigure}
-       \begin{subfigure}[b]{.3\linewidth}
-               \includegraphics[width=\linewidth]{home_auto2}
+       \end{subfigure}%
+       \begin{subfigure}{.33\linewidth}
+               \includegraphics[width=.9\linewidth]{home_auto2}
                \caption{Select device.}%
                \label{fig:example_screenshots2}
-       \end{subfigure}
-       \begin{subfigure}[b]{.3\linewidth}
-               \includegraphics[width=\linewidth]{home_auto3}
+       \end{subfigure}%
+       \begin{subfigure}{.33\linewidth}
+               \includegraphics[width=.9\linewidth]{home_auto3}
                \caption{View result.}%
                \label{fig:example_screenshots3}
        \end{subfigure}
@@ -283,11 +288,9 @@ Finally, a task that calculates the factorial of a user-provided number is shown
 \end{figure}
 
 \begin{figure}[p]
-       \begin{fullpage}
-               \cleaninputlisting[firstline=12,lastline=50,numbers=left,belowskip=0pt]{lst/example.icl}
-               \begin{lstClean}[numbers=left,firstnumber=40,aboveskip=0pt,caption={An example of a home automation program.},label={lst:example_home_automation}]
+               \cleaninputlisting[firstline=12,lastline=49,numbers=left,belowskip=0pt,basicstyle=\tt\footnotesize]{lst/example.icl}
+               \begin{lstClean}[numbers=left,firstnumber=39,aboveskip=0pt,basicstyle=\tt\footnotesize,caption={An example of a home automation program.},label={lst:example_home_automation}]
        , ...][+\label{lst:example:tasks2}+]\end{lstClean}
-       \end{fullpage}
 \end{figure}
 
 \input{subfilepostamble}
index d6bb86c..d1f6222 100644 (file)
@@ -7,7 +7,7 @@ import mTask.Interpret
 import mTask.Interpret.Device.TCP
 import mTask.Interpret.Device.Serial
 
-//Start w = doTasks autoHome w
+Start w = doTasks autoHome w
 
 arduino = {TTYSettings | zero & devicePath="/dev/ttyACM0"}/*\label{lst:example:spec1}*/
 nodeMCU = {TCPSettings | host="192.168.0.1", port=8123, pingTimeout= ?None}/*\label{lst:example:spec2}*/
@@ -26,10 +26,9 @@ chooseTask dev1 dev2 stl = tune (Title "Run a task") $
        >>? \device->appendTask Embedded (mkTask n i device) stl
        >-| chooseTask dev1 dev2 stl
 where
-       mkTask n i device stl
-               # dev = if (device == "node") dev2 dev1
-               = ((snd (tasks !! i) $ dev)
-                       >>* [OnAction ActionClose $ always $ return ()]) <<@ Title n/*\label{lst:example:ct2}*/
+       mkTask n i device stl = ((snd (tasks !! i) $ dev)
+               >>* [OnAction ActionClose $ always $ return ()]) <<@ Title n/*\label{lst:example:ct2}*/
+       where dev = if (device == "node") dev2 dev1
 
 tasks :: [(String, MTDevice -> Task ())]/*\label{lst:example:tasks1}*/
 tasks =
@@ -71,7 +70,3 @@ lightswitch sh =
                >>*. [IfValue ((!=.)st) (\v->writeD d13 v)]
                >>|. f (Not st))
        In {main=f true}
-
-Start w = doTasks t w
-t = withShared True \sh->
-       updateSharedInformation [] sh <<@ Hint "Light switch"
index 2b5ac47..e541a06 100644 (file)
@@ -36,7 +36,7 @@ Conventional \gls{IOT} software architectures require the development of separat
        \item The developer must deal with the potentially diverse failure modes of each component, and of component interoperation.
 \end{enumerate*}
 
-A radical alternative development paradigm uses a single \emph{tierless} language that synthesizes all components\slash{}tiers in the software stack. There are established \emph{tierless} languages for web stacks, e.g.\ Links \citep{cooper2006links} or Hop \citep{serrano2006hop}.
+A radical alternative development paradigm uses a single \emph{tierless} language that synthesises all components\slash{}tiers in the software stack. There are established \emph{tierless} languages for web stacks, e.g.\ Links \citep{cooper2006links} or Hop \citep{serrano2006hop}.
 In a tierless language the developer writes the application as a single program. The code for different tiers is simultaneously checked by the compiler, and compiled to the required component languages. For example, Links compiles to HTML and JavaScript for the web client and to SQL on the server to interact with the database system. Tierless languages for \gls{IOT} stacks are more recent and less common, examples include
 Potato \citep{troyer_building_2018} and \gls{CLEAN} with \imtask{} \citep{lubbers_interpreting_2019}.
 
@@ -520,6 +520,7 @@ While this simple application makes limited use of the \gls{MTASK} \gls{EDSL}, i
 Function composition (\cref{lst_t4t:mtasktemp:o}) and currying (\cref{lst_t4t:mtasktemp:setSds}) are inherited from the \gls{CLEAN} host language.
 As \gls{MTASK} tasks are dynamically compiled, it is also possible to select and customise tasks as required at runtime.
 For example, the interval used in the \cleaninline{rpeatevery} task (\cref{lst_t4t:mtasktemp:rpeatevery}) could be a parameter to the \cleaninline{devTask} function.
+\newpage%
 
 \begin{lstClean}[%
        numbers=left,
@@ -555,7 +556,7 @@ devTask =
 
 mainTask :: Task Real
 mainTask
-       =   withDevice deviceInfo \dev -> liftmTask} devTask dev[+\label{lst_t4t:mtasktemp:liftmtask}+][+\label{lst_t4t:mtasktemp:withdevice}+][+\label{lst_t4t:mtasktemp:co2}\srcmark{CO}+]
+       =   withDevice deviceInfo \dev -> liftmTask devTask dev[+\label{lst_t4t:mtasktemp:liftmtask}+][+\label{lst_t4t:mtasktemp:withdevice}+][+\label{lst_t4t:mtasktemp:co2}\srcmark{CO}+]
        -|| viewSharedInformation [] latestTemp[+\label{lst_t4t:mtasktemp:wi1}\srcmark{WI}+]
        <<@ Title "Latest temperature"[+\label{lst_t4t:mtasktemp:wi2}\srcmark{WI}+]
 \end{lstClean}
@@ -687,11 +688,10 @@ Observation of the four implementations shows that they operate as expected, e.g
 All four implementations use an identical set of inexpensive sensors, so we expect the accuracy of the data collected is within tolerance levels. This is validated by comparing \gls{PRS} and \gls{PWS} sensor nodes deployed in the same room for some minutes. The measurements show only small variances, e.g.\ temperatures recorded differ by less than \qty{0.4}{\celcius}, and light by less than \qty{1}{lux}. For this room monitoring application precise timings are not critical, and we don't compare the timing behaviours of the implementations.
 
 \subsubsection{Memory and power consumption}%
-%\subsubsection{Memory Consumption}%
 \label{sec_t4t:MemPower}
 
 \paragraph{Memory} By design sensor nodes are devices with limited computational capacity, and memory is a key restriction. Even supersensors often have less than a \unit{\gibi\byte} of memory, and microcontrollers often have just tens of \unit{\kibi\byte}.
-As the tierless languages synthesize the code to be executed on the sensor nodes, we need to confirm that the generated code is sufficiently memory efficient.
+As the tierless languages synthesise the code to be executed on the sensor nodes, we need to confirm that the generated code is sufficiently memory efficient.
 
 \begin{table}
        \centering
@@ -844,14 +844,14 @@ A caveat is that the smart campus system is relatively simple, and developing mo
                \midrule
                Code Location & Functionality & \gls{PYTHON} & \gls{CLEAN}\\
                \midrule
-               Sensor Node   & Sensor Int.   & imperative   & declarative\\
-                             & Sensor Node   & imperative   & declarative\\
+               Sensor Node   & Sensor Interface   & Imperative   & Declarative\\
+                             & Sensor Node   & Imperative   & Declarative\\
                \midrule
-               Server        & Manage Nodes  & imperative   & declarative\\
-                             & Web Int.      & both         & declarative\\
-                             & Database Int. & both         & declarative\\
+               Server        & Manage Nodes  & Imperative   & Declarative\\
+                             & Web Interface      & Both         & Declarative\\
+                             & Database Interface & Both         & Declarative\\
                \midrule
-               Communication & Communication & imperative   & declarative\\
+               Communication & Communication & Imperative   & Declarative\\
                \midrule
                              & Total         & 2            & 1 \\
                \bottomrule
@@ -867,7 +867,6 @@ Interoperation \emph{increases the cognitive load on the developer} who must sim
 The developer must \emph{correctly interoperate the components}, e.g.\ adhere to the \gls{API} or communication protocols between components. The interoperation often entails additional programming tasks like marshalling or unmarshalling data between components. For example, in the tiered \gls{PRS} and \gls{PWS} architectures, \gls{JSON} is used to serialise and deserialise data strings from the \gls{PYTHON} collector component before storing the data in the Redis database (\cref{lst_t4t:json}).
 
 \begin{lstPython}[caption={\Gls{JSON} Data marshalling in \gls{PRS} and \gls{PWS}: sensor node above, server below.},label={lst_t4t:json}]
-
 channel = 'sensor_status.%s.%s' % (hostname,
        sensor_types.sensor_type_name(s.sensor_type))
                self.r.publish(channel, s.SerializeToString())
@@ -920,7 +919,7 @@ The exchange of data, user interface, and communication are all automatically ge
 
 Another reason that the tierless \gls{CLEAN} implementations are concise is because they use powerful higher order \gls{IOT} programming abstractions.
 For comprehensibility the simple temperature sensor from \cref{sec_t4t:mtasks} (\cref{lst_t4t:mtasktemp}) is used to compare the expressive power of \gls{CLEAN} and \gls{PYTHON}-based \gls{IOT} programming abstractions.
-There are implementations for all four configurations: \gls{PRTS} (\gls{PYTHON} Raspberry Pi Temperature Sensor)\footnotemark, \gls{PWTS}\footnotemark[\value{footnote}],
+There are implementations for all four configurations: \gls{PRTS}\footnotemark, \gls{PWTS}\footnotemark[\value{footnote}],
 \footnotetext{Lubbers, M.; Koopman, P.; Ramsingh, A.; Singer, J.; Trinder, P. (2021): Source code, line counts and memory stats for PRS, PWS, PRT and PWT.\ Zenodo.\ \href{https://doi.org/10.5281/zenodo.5081386}{10.5281/zenodo.5081386}.} \gls{CRTS}\footnotemark{} and \gls{CWTS}\footnotemark[\value{footnote}].
 \footnotetext{Lubbers, M.; Koopman, P.; Ramsingh, A.; Singer, J.; Trinder, P. (2021): Source code, line counts and memory stats for CRS, CWS, CRTS and CWTS.\ Zenodo.\ \href{https://doi.org/10.5281/zenodo.5040754}{10.5281/zenodo.5040754}.}
 but as the programming abstractions are broadly similar, we compare only the \gls{PWTS} and \gls{CWTS} implementations.
@@ -1009,7 +1008,7 @@ failover :: [TCPSettings] (Main (MTask BCInterpret a)) -> Task a
 failover []     _     = throw "Exhausted device pool"
 failover [d:ds] mtask = try (withDevice d (liftmTask mtask)) except
 where except MTEUnexpectedDisconnect = failover ds mtask
-         except _                       = throw e
+         except e                       = throw e
 \end{lstClean}
 
 In the \gls{UOG} smart campus application, this can be done by creating a pool of sensor nodes for each room and when a sensor node fails, assign another one to the task.
@@ -1042,6 +1041,7 @@ In summary, while a tiered approach makes replacing components easy, refactoring
 \label{sec_t4t:support}
 Community and tool support are essential for engineering reliable production software. \Gls{PRS} and \gls{PWS} are both \gls{PYTHON} based, and \gls{PYTHON}\slash\gls{MICROPYTHON} are among the most popular programming languages \citep{cass2020top}. \Gls{PYTHON} is also a common choice for some tiers of \gls{IOT} applications \citep{tanganelli2015coapthon}.
 Hence, there are a wide range of development tools like \glspl{IDE} and debuggers, a thriving community and a wealth of training material. There are even specialised \gls{IOT} Boards like PyBoard \& WiPy that are specifically programmed using \gls{PYTHON} variations like \gls{MICROPYTHON}.
+\pagebreak
 
 In contrast, tierless languages are far less mature than the languages used in tiered stacks, and far less widely adopted.
 This means that for \gls{CWS} and \gls{CRS} there are fewer tools, a far smaller developer community, and less training material available.
@@ -1064,7 +1064,7 @@ This section compares the \gls{ITASK} and \gls{MTASK} \glspl{EDSL}, with referen
 
 \begin{table}
        \small
-       \caption{Comparing tierless \gls{IOT} languages for resource-rich sensor nodes (\gls{ITASK} \gls{EDSL}), for resource-constrained sensor nodes (\gls{MTASK} \gls{EDSL}), and their \gls{CLEAN} host language.}%
+       \caption{Comparing tierless \gls{IOT} \glspl{DSL} for resource-rich sensor nodes (\gls{ITASK}), for resource-constrained sensor nodes (\gls{MTASK}), and their \gls{CLEAN} host language.}%
        \label{table_t4t:languagecomparison}
        \begin{tabular}{llll}
                \toprule
@@ -1079,10 +1079,10 @@ This section compares the \gls{ITASK} and \gls{MTASK} \glspl{EDSL}, with referen
                User-defined datatypes      & Yes    & Yes         & No \\
                Task oriented               & No     & Yes         & Yes \\
                Higher-order tasks          & {--}   & Yes         & No \\
-               Execution Target & Commodity PC & Commodity PC & microcontroller\\
-                                &              & and Browser & microcontroller\\
+               Execution Target & Commodity PC & Commodity PC & Microcontroller\\
+                                &              & and browser & Microcontroller\\
                Language Implementation & Compiled or & Compiled and & Interpreted\\
-                                       & interpreted & interpreted & Interpreted\\
+                                       & interpreted & interpreted & \\
                \bottomrule
        \end{tabular}
 \end{table}