X-Git-Url: https://git.martlubbers.net/?a=blobdiff_plain;f=top%2Flang.tex;h=d0945c9591aec48b49b1e6c0f29e49a86d649d0f;hb=40c364b9de5d27b8afedcfd83d76499acc9e31af;hp=f7e9ec307cb37bea0c3b0b402934729ad175ef1c;hpb=4c449b205b49b4773934bd5cfd22e0f15e199eeb;p=phd-thesis.git diff --git a/top/lang.tex b/top/lang.tex index f7e9ec3..d0945c9 100644 --- a/top/lang.tex +++ b/top/lang.tex @@ -2,6 +2,8 @@ \input{subfilepreamble} +\setcounter{chapter}{3} + \begin{document} \input{subfileprefix} \chapter{The \texorpdfstring{\gls{MTASK}}{mTask} language}%\texorpdfstring{\glsxtrshort{DSL}}{DSL}}% @@ -10,34 +12,131 @@ \noindent This chapter introduces the \gls{TOP} language \gls{MTASK} language by: \begin{itemize} \item introducing the setup of the \gls{EDSL}; - \item and showing the language interface and examples for the type system, data types, expressions, tasks and their combinators. + \item describing briefly the various interpretations; + \item and showing the language interface for: + \begin{itemize} + \item the types; + \item expressions, datatypes, and functions; + \item tasks and task combinators; + \item and \glspl{SDS}. + \end{itemize} \end{itemize} \end{chapterabstract} The \gls{MTASK} system is a complete \gls{TOP} programming environment for programming microcontrollers. This means that it not only contains a \gls{TOP} language but also a \gls{TOP} engine. -It is implemented as an \gls{EDSL} in \gls{CLEAN} using class-based---or tagless-final---embedding (see \cref{sec:tagless-final_embedding}). Due to the nature of the embedding technique, it is possible to have multiple interpretations for programs written in the \gls{MTASK} language. -Not all of these intepretations are necessarily \gls{TOP} engines, some may perform an analysis over the program or typeset the program so that the output can be shown after evaluating the expression at run time. -The following interpretations are available for \gls{MTASK}. +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}). +This means that the language is a collection of type classes and interpretations are data types implementing these classes. +Consequently, the language is extensible both in language constructs and in intepretations. +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. +Let us illustrate this by taking the very simple language of literal values. +This language interface can be described using a single type constructor class with a single function \cleaninline{lit}. +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}. + +\begin{lstClean} +class literals v where + lit :: a -> v a | toString a +\end{lstClean} + +Providing an evaluator is straightforward as can be seen in the following listing. +The evaluator is just a box holding a value of the computation but could also be some monadic computation. + +\begin{lstClean} +:: Eval a = Eval a + +runEval :: (Eval a) -> a +runEval (Eval a) = a + +instance literals Eval where + lit a = Eval a +\end{lstClean} + +Extending our language with a printer happens by defining a new data type and providing instances for the type constructor classes. +The printer stores a printed representation and hence the type is just a phantom type. + +\begin{lstClean} +:: Printer a = Printer String + +runPrinter :: (Printer a) -> String +runPrinter (Printer a) = a + +instance literals Printer where + lit a = Printer (toString a) +\end{lstClean} + +Finally, adding language constructs happens by defining new type classes and giving implementations for some of the interpretations. +The following listing adds an addition construct to the language and shows implementations for the evaluator and printer. -\begin{description} - \item[Printer] +\begin{lstClean} +class addition v where + add :: v a -> v a -> v a | + a - This interpretation converts the expression to a string representation. - As the host language \gls{CLEAN} constructs the \gls{MTASK} expressions at run time, it can be useful to show the constructed expression. - \item[Simulator] +instance addition Eval where + add (Eval l) (Eval r) = Eval (l + r) - 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. - \item[Byte code compiler] +instance addition Printer where + add (Printer l) (Printer r) = Printer ("(" +++ l +++ "+" +++ r +++ ")") +\end{lstClean} + +Terms in our little toy language can be overloaded in their interpretation, they are just an interface. +For example, $1+5$ is written as \cleaninline{add (lit 1) (lit 5)} and has the type \cleaninline{v Int \| literals, addition v}. +However, due to the way polymorphism is implemented in most functional languages, it is not always straightforward to use multiple interpretations in one function. +Creating such a function, e.g.\ one that both prints and evaluates an expression, requires rank-2 polymorphism (see \cref{lst:rank2_mtask}). + +\section{Interpretations} +This section describes all \gls{MTASK}'s interpretations. +Not all of these interpretations are necessarily \gls{TOP} engines, i.e.\ not all of the interpretations execute the terms/tasks. +Some may perform an analysis over the program or typeset the program so that a textual representation can be shown. + +\subsection{Pretty printer} +This interpretation converts the expression to a string representation. +As the host language \gls{CLEAN} constructs the \gls{MTASK} expressions at run time, it can be useful to show the constructed expression. +The only function exposed for this interpretation is the \cleaninline{showMain} (\cref{lst:showmain}) function. +It runs the pretty printer and returns a list of strings containing the pretty printed result as shown in \cref{lst:showexample}. +The pretty printing function does the best it can but obviously cannot reproduce the layout, curried functions and variable names. +This shortcoming is illustrated by the example application for blinking a single \gls{LED} using a function and currying in \cref{lst:showexample}. + +\begin{lstClean}[caption={The entrypoint for the pretty printing interpretation.},label={lst:showmain}] +:: Show a // from the mTask Show library +showMain :: (Main (Show a)) -> [String] | type a +\end{lstClean} + +\begin{lstClean}[caption={Pretty printing interpretation example.},label={lst:showexample}] +blinkTask :: Main (MTask v Bool) | mtask v +blinkTask = + fun \blink=(\state-> + writeD d13 state >>|. delay (lit 500) >>=. blink o Not + ) In {main = blink true} + +// output: +// fun f0 a1 = writeD(D13, a1) >>= \a2.(delay 1000) >>| (f0 (Not a1)) in (f0 True) +\end{lstClean} + +\subsection{Simulator} +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. +The task resulting from the \cleaninline{simulate} function presents the user with an interactive simulation environment (see \cref{lst:simulatemain,fig:sim}). +From within the interactive application, tasks can be (partly) executed, peripheral states changed and \glspl{SDS} interacted with. + +\begin{lstClean}[caption={The entrypoint for the simulation interpretation.},label={lst:simulatemain}] +:: TraceTask a // from the mTask Show library +simulate :: (Main (TraceTask a)) -> [String] | type a +\end{lstClean} + +\begin{figure} + \centering + \includegraphics[width=\linewidth]{simg} + \caption{Simulator interface for the blink program.}\label{fig:sim} +\end{figure} - The compiler compiles the \gls{MTASK} program to a specialised byte code. - Using a handful of integration functions and tasks (see \cref{chp:integration_with_itask}), \gls{MTASK} tasks can be executed on microcontrollers and integrated in \gls{ITASK} as if they were regular \gls{ITASK} tasks. - Furthermore, with special language constructs, \glspl{SDS} can be shared between \gls{MTASK} and \gls{ITASK} programs. -\end{description} +\subsection{Byte code compiler} +The main interpretation of the \gls{MTASK} system is the byte code compiler. +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. +Furthermore, with a special language construct, \glspl{SDS} can be shared between \gls{MTASK} and \gls{ITASK} programs as well. +This interface is explained thoroughly in \cref{chp:integration_with_itask}. When using the byte code compiler interpretation in conjunction with the \gls{ITASK} integration, \gls{MTASK} is a heterogeneous \gls{DSL}. -I.e.\ some components---e.g.\ the \gls{RTS} on the microcontroller---is largely unaware of the other components in the system, and it is executed on a completely different architecture. +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. 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}). \section{Types}