Skip to content

Commit

Permalink
Update to submitted version of TFP paper
Browse files Browse the repository at this point in the history
  • Loading branch information
Edwin Brady committed Jul 6, 2011
1 parent 5c7e5b1 commit 421da3d
Show file tree
Hide file tree
Showing 7 changed files with 180 additions and 139 deletions.
82 changes: 38 additions & 44 deletions Papers/Epic-TFP/bigexample.tex
Expand Up @@ -137,19 +137,17 @@ \subsection{Compiling}

While Atuin is a different kind of language from the
$\lambda$-calculus, with complicating factors such as a global state
(the turtle). imperative features, and dynamic type checking, the
(the turtle), imperative features, and dynamic type checking, the
process of constructing a compiler follows the same general recipe, i.e.
define primitive operations as Epic functions, then convert each Atuin
definition into the corresponding Epic definition.

\subsubsection{Compiling Primitives}

The first step in defining a compiler for Atuin is to define primitive
operations as Epic functions.
The language is dynamically
typed, therefore we will need primitive operations to check that they
are operating on the correct types. We define functions which
construct Epic code for
The first step is to define primitive operations as Epic functions.
The language is dynamically typed, therefore we will need primitive
operations to check dynamically that they are operating on values of
the correct type. We define functions which construct Epic code for
building values, effectively using a single algebraic datatype to
capture all possible run-time values (i.e. values are
``uni-typed''~\cite{wadlerblame}).
Expand All @@ -166,21 +164,20 @@ \subsubsection{Compiling Primitives}

\noindent
Correspondingly, we can extract the concrete values safely from this
structure, checking that the value is the required type:
structure, checking that the value is the required type, e.g.:

\begin{SaveVerbatim}{epicgetval}

getInt x = case_ x
[con 0 (\ (x :: Expr) -> x),
defaultcase (error_ "Not an Int")]
getInt x = case_ x [con 0 (\ (x :: Expr) -> x),
defaultcase (error_ "Not an Int")]

\end{SaveVerbatim}
\useverb{epicgetval}

\noindent
Similarly, \texttt{getChar}, \texttt{getBool} and \texttt{getCol}
check and extract values of the appropriate type.
Using these, it is simple to define primitve arithmetic operations
Using these, it is simple to define primitive arithmetic operations
which check they are operating on the correct type, and report an
error if not.

Expand All @@ -190,7 +187,6 @@ \subsubsection{Compiling Primitives}
primMinus x y = mkint $ op_ minus_ (getInt x) (getInt y)
primTimes x y = mkint $ op_ times_ (getInt x) (getInt y)
primDivide x y = mkint $ op_ divide_ (getInt x) (getInt y)

\end{SaveVerbatim}
\useverb{primops}

Expand All @@ -204,9 +200,8 @@ \subsubsection{Graphics Operations}
\begin{SaveVerbatim}{sdlglue}

void* startSDL(int x, int y);
void drawLine(void* surf,
int x, int y, int ex, int ey,
int r, int g, int b, int a);
void drawLine(void* surf, int x, int y, int ex, int ey,
int r, int g, int b, int a);

\end{SaveVerbatim}
\useverb{sdlglue}
Expand All @@ -220,15 +215,14 @@ \subsubsection{Graphics Operations}

We represent colours as a 4-tuple $(\vr,\vg,\vb,\va)$. Drawing a line
in Epic involves extracting the red, green, blue and alpha components
from this tuple, then calling the C \texttt{drawLine} function. Recall
that to make a foreign function call, we give the types of each
argument explicitly so that Epic will know how to convert from
internal values to C values:
from this tuple, then calling the C \texttt{drawLine} function. To
make a foreign function call, we use \texttt{foreign\_}, giving the C
function name and explicit types for each argument so that Epic
will know how to convert from internal values to C values:

\begin{SaveVerbatim}{drawline}

drawLine :: Expr -> Expr -> Expr ->
Expr -> Expr -> Expr -> Term
drawLine :: Expr -> Expr -> Expr -> Expr -> Expr -> Expr -> Term
drawLine surf x y ex ey col
= case_ (rgba col)
[tuple (\ r g b a ->
Expand All @@ -240,17 +234,17 @@ \subsubsection{Graphics Operations}
\end{SaveVerbatim}
\useverb{drawline}

When we compile Atuin programs, we treat the turtle state as a tuple
\noindent
The turtle state is a tuple
$(\vs,\vx,\vy,\vd,\vc,\vp)$ where $\vs$ is a pointer to the SDL
surface, $\vx$ and $\vy$ give the turtle's location, $\vd$ gives the
turtle's direction, $\vc$ gives the colour and $\vp$ gives the pen
surface, ($\vx$, $\vy$) gives the turtle's location, $\vd$ gives its
direction, $\vc$ gives the colour and $\vp$ gives the pen
state (a boolean, false for up and true for down). Note that this
state is not accessible by the programmer, so we do not need any
dynamic type checking of each component.

state is not accessible by Atuin programs, so we do not dynamically check
each component.
To implement the \texttt{forward} operation, for example, we take the
current turtle state, update the position according to the distance
given and the current direction, and if the pen us down, draws a line
current state, update the position according to the distance
given and the current direction, and if the pen is down, draws a line
from the old position to the new position.

\begin{SaveVerbatim}{drawfwd}
Expand All @@ -277,32 +271,32 @@ \subsubsection{Graphics Operations}

\subsubsection{Compiling Programs}

Programs return an updated turtle state, and possibly perform some
side-effects such as drawing. We can think of Atuin definitions with
arguments $\va_1$ to $\va_n$ as being translated to an Epic function
Programs return an updated turtle state, and possibly perform
side-effects such as drawing. An Atuin definition with
arguments $\va_1\ldots\va_n$ is translated to an Epic function
with a type of the following form:

\DM{
\vf \Hab \VV{State} \to \va_1 \to \ldots \to \va_n \to \VV{State}
}

\noindent
To compile a complete program, we add the primitive functions we have
defined above (line drawing, turtle movement, etc) to the list of
basic Epic definitions, and convert the user defined procedures to Epic.

\begin{SaveVerbatim}{prims}

prims = basic_defs ++
[EpicFn (name "initSDL") initSDL,
EpicFn (name "drawLine") drawLine,
EpicFn (name "forward") forward, ... ]
prims = basic_defs ++ [EpicFn (name "initSDL") initSDL,
EpicFn (name "drawLine") drawLine,
EpicFn (name "forward") forward, ... ]

\end{SaveVerbatim}
\useverb{prims}

\noindent
We will need to convert expressions, commands and full programs into
Epic terms, so define a type class to capture all of these. Programs
We define a type class to capture conversion of expressions, commands
and full programs into Epic terms. Programs
maintain the turtle's state (an Epic \texttt{Expr}), and return a new
state, so we pass this state to the compiler.

Expand All @@ -314,6 +308,7 @@ \subsubsection{Compiling Programs}
\end{SaveVerbatim}
\useverb{compileclass}

\noindent
In general, since we have set up all of the primitive operations as
Epic functions, compiling an Atuin program consists of directly
translating the abstract syntax to the Epic equivalent, making sure
Expand All @@ -324,8 +319,7 @@ \subsubsection{Compiling Programs}

\begin{SaveVerbatim}{compfn}

compile state (Call i es)
= app (fn fullId i) @@ state) es
compile state (Call i es) = app (fn fullId i) @@ state) es
where app f [] = f
app f (e:es) = app (f @@ compile state e) es

Expand Down Expand Up @@ -371,9 +365,8 @@ \subsubsection{Compiling Programs}

\begin{SaveVerbatim}{runmain}

init_turtle surf = tuple_ @@ surf @@
int 320 @@ int 240 @@ int 180 @@
col_white @@ bool True
init_turtle surf = tuple_ @@ surf @@ int 320 @@ int 240 @@
int 180 @@ col_white @@ bool True

runMain :: Term
runMain = let_ (fn "initSDL" @@ int 640 @@ int 480)
Expand All @@ -384,6 +377,7 @@ \subsubsection{Compiling Programs}
\end{SaveVerbatim}
\useverb{runmain}

\noindent
The full source code for Atuin and its compiler is available from
Hackage (\url{http://hackage.haskell.org/package/atuin}), which
covers the remaining technical details of linking compiled programs
Expand Down
47 changes: 32 additions & 15 deletions Papers/Epic-TFP/conclusions.tex
Expand Up @@ -12,11 +12,14 @@ \section{Related Work}
Epic uses techniques from other functional language back
ends~\cite{evalpush,stg,abc-machine} but deliberately exposes its core
language as an API to make it as reusable as possible. Although there
is likely to always be a trade off between reusability and efficiency,
is always likely to be a trade off between reusability and efficiency,
exposing the API will make it easier for other language researchers to
build a new compiler quickly. The Lazy Virtual Machine~\cite{lvm} has
similar goals but it designed as a lower level target language, rather
than a high level API.
than a high level API. C\texttt{--}~\cite{c--} and LLVM~\cite{llvm} are also
tools for generating language back ends, but are similarly low level and
do not provide direct support for functional features. We could
nevertheless consider using these tools for Epic code generation.

%C--~\cite{c--} and LLVM~\cite{llvm}
%as possible code generation strategies. Supercompilation for
Expand All @@ -31,28 +34,42 @@ \section{Conclusion}
well-understood but difficult to implement problems such as lambda
lifting, code generation, interfacing with foreign functions and
garbage collection.

In this paper we have seen two examples of languages which can be
compiled via Epic, both functionally based, but with different
features. The high-level recipe for each is the same: define primitive
functions as run-time support, then translate the abstract syntax into
concrete Epic functions, using a combinator style API.
concrete Epic functions, using a combinator style API. In addition,
we have implemented a compiler for \LamPi{}~\cite{simply-easy}, a
dependently typed language, which shows how Epic can handle languages
with more expressive type
systems\footnote{\url{http://www.idris-lang.org/examples/LambdaPi.hs}}.


\subsubsection{Future work}

Epic is currently used in practice by a dependently typed functional
language, Idris~\cite{plpv11}, and experimentally by
Agda~\cite{norell-thesis} and Epigram~\cite{levitation}. Future work
will therefore have an emphasis on providing an efficient executable
environment for these and related languages. An interesting research
question, for example, is whether the rich type systems of these languages
can be used to guide optimisation, and if so how to present the
information gained by the type system to the compiler.
%Epic is currently used in practice by a dependently typed functional
%language, Idris~\cite{plpv11}, and experimentally by
%Agda~\cite{norell-thesis} and Epigram~\cite{levitation}.

Since Epic is currently used in practice by a number of dependently
typed functional languages, future work will have an emphasis on
providing an efficient executable environment for these and related
languages. An interesting research question, for example, is whether
the rich type systems of these languages can be used to guide
optimisation, and if so how to present the information gained by the
type system to the compiler.

Currently, Epic compiles to machine code via C, using the Boehm
conservative garbage collector~\cite{boehm-gc}. While this has been
reasonably efficient in practice, we believe that an LLVM based
implementation~\cite{llvm,llvm-haskell} with accurate garbage
collection would be more appropriate. Of course, any language which
uses Epic as a back end will stand to gain from future optimisation
efforts!
collection would be more appropriate as it could take advantage of
functional language features such as immutability of data.

Perhaps more importantly, as a very simple functional language Epic is
a convenient platform with which to experiment with functional
compilation techniques. For example, we are developing an evaluator
which will be a starting point for experimenting with
supercompilation~\cite{mitchell-super} and partial evaluation.
Of course, any language which uses Epic as a back end will stand to
gain from future optimisation efforts!
12 changes: 6 additions & 6 deletions Papers/Epic-TFP/epic.tex
Expand Up @@ -66,12 +66,12 @@
well understood, it remains difficult for a new functional language to
exploit these techniques without either implementing a compiler from
scratch, or attempting fit the new language around another existing
compiler.
Epic is a compiled functional language which exposes functional
compilation techniques to a language implementor, with a Haskell
API. In this paper we describe Epic and outline how it may
be used to implement a high level language compiler, illustrating our
approach using a dynamically typed graphics language.
compiler. Epic is a compiled functional language which exposes
functional compilation techniques to a language implementor, with a
Haskell API. In this paper we describe Epic and outline how it may be
used to implement a high level language compiler, illustrating our
approach by implementing compilers for the $\lambda$-calculus and a
dynamically typed graphics language.

\end{abstract}

Expand Down
49 changes: 27 additions & 22 deletions Papers/Epic-TFP/example.tex
Expand Up @@ -3,23 +3,24 @@ \section{Example --- Compiling the $\lambda$-Calculus}
\label{sec:lc}

In this section we present a compiler for a simple high level
language.
This is a compiler for the untyped $\lambda$-calculus using Higher Order
Abstract Syntax, which shows the fundamental features of Epic required
to implement a complete compiler. We have also implemented compilers
for \LamPi{}~\cite{simply-easy}, a dependently typed language, which
shows how Epic can handle languages with more expressive type systems,
and a dynamically typed graphics language\footnote{\url{http://hackage.haskell.org/package/atuin}}, which shows how Epic can be
used for languages with run-time type checking and which require
foreign function calls.
language, the untyped $\lambda$-calculus using higher order abstract
syntax. This shows the fundamental features of Epic required to
implement a complete compiler.

%We have also implemented compilers
%for \LamPi{}~\cite{simply-easy}, a dependently typed language, which
%shows how Epic can handle languages with more expressive type systems,
%and a dynamically typed graphics language\footnote{\url{http://hackage.haskell.org/package/atuin}}, which shows how Epic can be
%used for languages with run-time type checking and which require
%foreign function calls.

\subsection{Representation}

Our example is an implementation of the untyped
$\lambda$-calculus, plus primitive integers and strings, and
arithmetic and string operators. The language is represented in
Haskell using higher order abstract syntax (HOAS). That is, we
represent $\lambda$-bindings (\texttt{Lam}) as Haskell functions,
arithmetic and string operators. The Haskell representation uses
higher order abstract syntax (HOAS), i.e. we
represent $\lambda$-bindings (\texttt{Lam}) as functions,
using a Haskell variable name to refer to the locally bound
variable. We also include global references (\texttt{Ref}) which refer
to top level functions, function application (\texttt{App}), constants
Expand Down Expand Up @@ -82,8 +83,6 @@ \subsection{Compilation}
\begin{SaveVerbatim}{eprogs}

data EpicDecl = forall e. EpicExpr e => EpicFn Name e
| ...

type Program = [EpicDecl]

\end{SaveVerbatim}
Expand Down Expand Up @@ -168,16 +167,22 @@ \subsection{Compilation}
Given \texttt{build}, we can translate a collection of HOAS
definitions into an Epic program, add the built-in Epic definitions
and execute it directly. Recall that there must be a function called
\texttt{"main"} or Epic will report an error.
\texttt{"main"} or Epic will report an error --- we therefore add a
main function which prints the value of an integer expression
given at compile time.

\begin{SaveVerbatim}{lmain}

mkProgram :: Defs -> Program
mkProgram ds = basic_defs ++
map (\ (n, d) -> EpicFn n (build d)) ds
main_ exp = App (Ref (name "putStrLn"))
(App (Ref (name "intToString")) exp)

mkProgram :: Defs -> Lang -> Program
mkProgram ds exp = basic_defs ++
map (\ (n, d) -> EpicFn n (build d)) ds ++
[(name "main", main_ exp)]

execute :: Defs -> IO ()
execute p = run (mkProgram p)
execute :: Defs -> Lang -> IO ()
execute p exp = run (mkProgram p exp)

\end{SaveVerbatim}
\useverb{lmain}
Expand All @@ -188,8 +193,8 @@ \subsection{Compilation}

\begin{SaveVerbatim}{lcomp}

comp :: Defs -> IO ()
comp p = compile "a.out" (mkProgram p)
comp :: Defs -> Lang -> IO ()
comp p exp = compile "a.out" (mkProgram p exp)

\end{SaveVerbatim}
\useverb{lcomp}
Expand Down

0 comments on commit 421da3d

Please sign in to comment.