X-Git-Url: https://git.martlubbers.net/?a=blobdiff_plain;f=dsl%2Ffirst.tex;fp=dsl%2Ffirst.tex;h=4b508c52c2b2e8ce6bff9e81ab4c4e5347177ef1;hb=7abb270258db436c7a6bbc5d798858163420ab9f;hp=e269a22759535e7c374d44a5279366732acc4072;hpb=d6c8d6cbc9c88d449ac784eda20a213fd6b46669;p=phd-thesis.git diff --git a/dsl/first.tex b/dsl/first.tex index e269a22..4b508c5 100644 --- a/dsl/first.tex +++ b/dsl/first.tex @@ -74,7 +74,7 @@ infixl 6 +. The implementation of a view on the \gls{DSL} is achieved by implementing the type classes with the data type representing the view. In the case of our example \gls{DSL}, an interpreter accounting for failure may be implemented as an instance for the \haskellinline{Maybe} type. -The standard infix functor application and infix sequential application are used so that potential failure is abstracted away from.\footnotemark{} +The standard infix functor application and infix sequential application are used so that potential failure is abstracted away from\footnotemark. \begin{lrbox}{\LstBox} \begin{lstHaskell}[frame=] <$> :: (a -> b) -> f a -> f b @@ -113,7 +113,7 @@ instance Div Maybe where \subsection{Adding semantics} To add semantics to the \gls{DSL}, the existing classes are implemented with a novel data type representing the view on the \gls{DSL}. -First a data type representing the semantics is defined. In this case, the printer is kept very simple for brevity and just defined as a \haskellinline{newtype} of a string to store the printed representation.\footnotemark{} +First a data type representing the semantics is defined. In this case, the printer is kept very simple for brevity and just defined as a \haskellinline{newtype} of a string to store the printed representation\footnotemark. \footnotetext{% In this case a \haskellinline{newtype} is used instead of regular \haskellinline{data} declarations. \haskellinline{newtype}s are special data types only consisting a single constructor with one field to which the type is isomorphic. @@ -171,7 +171,7 @@ instance Function a Maybe where \end{lstHaskell} The given \haskellinline{Printer} type is not sufficient to implement the instances for the \haskellinline{Function} class, it must be possible to generate fresh function names. -After extending the \haskellinline{Printer} type to contain some sort of state to generate fresh function names and a \haskellinline{MonadWriter [String]}\footnotemark{} to streamline the output, we define an instance for every arity. +After extending the \haskellinline{Printer} type to contain some sort of state to generate fresh function names and a \haskellinline{MonadWriter [String]}\footnotemark\ to streamline the output, we define an instance for every arity. \begin{lrbox}{\LstBox} \begin{lstHaskell}[frame=] freshLabel :: Printer String @@ -208,7 +208,7 @@ Unfortunately, once lifted, it is not possible to do anything with values of the It is not possible to construct new values from expressions in the \gls{DSL}, to deconstruct a value into the fields, nor to test of which constructor the value is. Furthermore, while in the our language the only constraint is the automatically derivable \haskellinline{Show}, in real-world languages the class constraints may be very difficult to satisfy for complex types, for example serialisation to a single stack cell in the case of a compiler. -As a consequence, for user-defined data types---such as a pro\-gram\-mer-defined list type\footnotemark{}---to become first-class citizens in the \gls{DSL}, language constructs for constructors, deconstructors and constructor predicates must be defined. +As a consequence, for user-defined data types---such as a pro\-gram\-mer-defined list type\footnotemark---to become first-class citizens in the \gls{DSL}, language constructs for constructors, deconstructors and constructor predicates must be defined. Field selectors are also useful functions for working with user-defined data types, they are not considered for the sake of brevity but can be implemented using the deconstructor functions. \footnotetext{ For example: \haskellinline{data List a = Nil \| Cons \{hd :: a, tl :: List a\}} @@ -345,19 +345,19 @@ The \haskellinline{Info} type is an \gls{ADT} containing all the---known to the With the power of metaprogramming, we can generate the boilerplate code for our user-defined data types automatically at compile time. To generate the code required for the \gls{DSL}, we define the \haskellinline{genDSL} function. The type belonging to the name passed as an argument to this function is made available for the \gls{DSL} by generating the \haskellinline{typeDSL} class and view instances. -For the \haskellinline{List} type it is called as: \haskellinline{\$(genDSL ''List)}.\footnotemark{} +For the \haskellinline{List} type it is called as: \haskellinline{\$(genDSL ''List)}\footnotemark. \footnotetext{ \haskellinline{''} is used instead of \haskellinline{'} to instruct the compiler to look up the information for \haskellinline{List} as a type and not as a constructor. } The \haskellinline{genDSL} function is a regular function---though \gls{TH} requires that it is defined in a separate module---that has type: \haskellinline{Name -> Q [Dec]}, i.e.\ given a name, it produces a list of declarations in the \haskellinline{Q} monad. The \haskellinline{genDSL} function first reifies the name to retrieve the structural information. -If the name matches a type constructor containing a data type declaration, the structure of the type---the type variables, the type name and information about the constructors\footnotemark{}---are passed to the \haskellinline{genDSL'} function. +If the name matches a type constructor containing a data type declaration, the structure of the type---the type variables, the type name and information about the constructors\footnotemark---are passed to the \haskellinline{genDSL'} function. \footnotetext{ Defined as \haskellinline{type VarBangType = (Name, Bang, Type)} by \gls{TH}. } The \haskellinline{getConsName} function filters out unsupported data types such as \glspl{GADT} and makes sure that every field has a name. -For regular \glspl{ADT}, the \haskellinline{adtFieldName} function is used to generate a name for the constructor based on the indices of the fields\footnotemark{}. +For regular \glspl{ADT}, the \haskellinline{adtFieldName} function is used to generate a name for the constructor based on the indices of the fields\footnotemark. \footnotetext{ \haskellinline{adtFieldName :: Name -> Integer -> Name} } @@ -494,7 +494,7 @@ The interpreter is a view on the \gls{DSL} that immediately executes all operati Therefore, the constructor function can be implemented by lifting the actual constructor to the \haskellinline{Maybe} type using sequential application. I.e.\ for a constructor $C_k$ this results in the following constructor: \haskellinline{ck a0 ... am = pure Ck <*> a0 <*> ... <*> am}. To avoid accidental shadowing, fresh names for all the arguments are generated. -The \haskellinline{ifx} function is used as a shorthand for defining infix expressions.\footnotemark{} +The \haskellinline{ifx} function is used as a shorthand for defining infix expressions\footnotemark. \begin{lrbox}{\LstBox} \begin{lstHaskell}[frame=] ifx :: String -> Q Exp -> Q Exp -> Q Exp @@ -518,7 +518,7 @@ In the case of a deconstructor a function with two arguments is created: the obj To avoid accidental shadowing first fresh names for the arguments and fields are generated. Then, a function is created with the two arguments. First \haskellinline{d} is evaluated and bound to a host language function that deconstructs the constructor and passes the fields to \haskellinline{f}. -I.e.\ a deconstructor function $C_k$ is defined as: \haskellinline{unCk d f = d >>= \\(Ck a0 .. am)->f (pure a0) ... (pure am))}.\footnotemark{} +I.e.\ a deconstructor function $C_k$ is defined as: \haskellinline{unCk d f = d >>= \\(Ck a0 .. am)->f (pure a0) ... (pure am))}\footnotemark. \footnotetext{ The \haskellinline{nameBase :: Name -> String} function from the \gls{TH} library is used to convert a name to a string. } @@ -634,7 +634,7 @@ mkPredicate n = fun (predicateName n) [] \section{Pattern matching} It is possible to construct and deconstruct values from other \gls{DSL} expressions, and to perform tests on the constructor but with a clunky and unwieldy syntax. They have become first-class citizens in a grotesque way. -For example, given that we have some language constructs to denote failure and conditionals\footnotemark{}, writing a list summation function in our \gls{DSL} would be done as follows. +For example, given that we have some language constructs to denote failure and conditionals\footnotemark, writing a list summation function in our \gls{DSL} would be done as follows. For the sake of the argument we take a little shortcut here and assume that the interpretation of the \gls{DSL} supports lazy evaluation by using the host language as a metaprogramming language as well, allowing us to use functions in the host language to contstruct expressions in the \gls{DSL}. \begin{lrbox}{\LstBox}