Permalink
Browse files

Minor interface changes; final TFP paper

  • Loading branch information...
1 parent 9b56d0a commit d3593938acd14035656469abb182a9b828a0fd43 Edwin Brady committed Oct 15, 2011
View
@@ -27,7 +27,7 @@
> Type, tyInt, tyChar, tyBool, tyFloat, tyString,
> tyPtr, tyUnit, tyAny, tyC,
> -- * Operators
-> plus_, minus_, times_, divide_,
+> Op, plus_, minus_, times_, divide_,
> plusF_, minusF_, timesF_, divideF_,
> eq_, lt_, lte_, gt_, gte_,
> eqF_, ltF_, lteF_, gtF_, gteF_, shiftl_, shiftr_,
View
@@ -22,6 +22,7 @@ then we have an error. Returns expression in standard form.
> xs' <- mapM ev xs
> evFn f' xs'
> ev (Lazy e) = ev e
+> ev (Par e) = ev e
> ev (Effect e) = ev e
> ev (Con t es) = do es' <- mapM ev es
> return $ Con t es'
@@ -135,6 +136,7 @@ then we have an error. Returns expression in standard form.
> instance Quote Expr where
> quote v (App x xs) = App (quote v x) (quote v xs)
> quote v (Lazy x) = Lazy (quote v x)
+> quote v (Par x) = Par (quote v x)
> quote v (Effect x) = Effect (quote v x)
> quote v (Con t xs) = Con t (quote v xs)
> quote v (Proj x i) = Proj (quote v x) i
View
@@ -9,6 +9,7 @@
> import System.Environment
> import Debug.Trace
+> import Data.Char
> -- | (Debugging) options to give to compiler
> data CompileOptions = KeepC -- ^ Keep intermediate C file
@@ -88,7 +89,8 @@ Raw data types. Int, Char, Bool are unboxed.
> quotename ('$':cs) = "_DO_"++quotename cs
> quotename ('#':cs) = "_HA_"++quotename cs
> quotename ('@':cs) = "_AT_"++quotename cs
-> quotename (c:cs) = c:(quotename cs)
+> quotename (c:cs) | isAlphaNum c = c:(quotename cs)
+> | otherwise = "_" ++ show (fromEnum c) ++ "_" ++ quotename cs
> showC n = quotename (show n)
@@ -109,6 +111,7 @@ Get the arity of a definition in the context
> | App Expr [Expr] -- Function application
> | Lazy Expr -- Lazy function application
> | Effect Expr -- Expression with side effects (i.e. don't update when EVALing)
+> | Par Expr -- evaluate an expression in parallel
> | Con Tag [Expr] -- Constructor, tags, arguments (fully applied)
> | Const Const -- a constant
> | Proj Expr Int -- Project argument
@@ -178,6 +181,7 @@ Get the arity of a definition in the context
> show (R n) = show n
> show (App f as) = show f ++ show as
> show (Lazy e) = "%lazy(" ++ show e ++ ")"
+> show (Par e) = "%par(" ++ show e ++ ")"
> show (Effect e) = "%effect(" ++ show e ++ ")"
> show (Con t es) = "Con " ++ show t ++ show es
> show (Const c) = show c
@@ -250,6 +254,7 @@ Programs
> subst v rep (V x) | v == x = rep
> subst v rep (App x xs) = App (subst v rep x) (subst v rep xs)
> subst v rep (Lazy x) = Lazy (subst v rep x)
+> subst v rep (Par x) = Par (subst v rep x)
> subst v rep (Effect x) = Effect (subst v rep x)
> subst v rep (Con t xs) = Con t (subst v rep xs)
> subst v rep (Proj x i) = Proj (subst v rep x) i
@@ -296,6 +301,7 @@ Programs
> instance HOAS Expr Expr where
> hoas v (App f xs) = App (hoas v f) (hoas v xs)
> hoas v (Lazy x) = Lazy (hoas v x)
+> hoas v (Par x) = Par (hoas v x)
> hoas v (Effect x) = Effect (hoas v x)
> hoas v (Con t xs) = Con t (hoas v xs)
> hoas v (Proj x i) = Proj (hoas v x) i
View
@@ -116,6 +116,7 @@
> | TokenUnused
> | TokenIn
> | TokenLazy
+> | TokenPar
> | TokenStrict
> | TokenEffect
> | TokenError
@@ -268,6 +269,7 @@
> ("else",rest) -> cont TokenElse rest
> ("in",rest) -> cont TokenIn rest
> ("lazy",rest) -> cont TokenLazy rest
+> ("par",rest) -> cont TokenPar rest
> ("error",rest) -> cont TokenError rest
> ("impossible",rest) -> cont TokenImpossible rest
> ("foreign",rest) -> cont TokenForeign rest
View
@@ -59,6 +59,7 @@ import Epic.Lexer
unused { TokenUnused }
in { TokenIn }
lazy { TokenLazy }
+ par { TokenPar }
strict { TokenStrict }
effect { TokenEffect }
foreign { TokenForeign }
@@ -109,6 +110,7 @@ import Epic.Lexer
%nonassoc NONE
%nonassoc lazy
+%nonassoc par
%left LET
%left IF
%left eq feq
@@ -183,6 +185,7 @@ Expr : name { R $1 }
| Expr '(' ExprList ')' { App $1 $3 }
| '[' ExprList ']' { Con 0 $2 }
| lazy '(' Expr ')' { Lazy $3 }
+ | par '(' Expr ')' { Par $3 }
| effect '(' Expr ')' { Effect $3 }
| con int '(' ExprList ')' { Con $2 $4 }
| Const { Const $1 }
View
@@ -91,6 +91,9 @@ Do Lambda Lifting here too
> tc env (Lazy e) | appForm e = do
> e' <- tc env e
> return $ Lazy e'
+> tc env (Par e) | appForm e = do
+> e' <- tc env e
+> return $ Par e'
Make a new function, with current env as arguments, and add as a decl
@@ -102,6 +105,14 @@ Make a new function, with current env as arguments, and add as a decl
> let newd = Decl newname TyAny newfn Nothing []
> put (maxlen, nextn+1, newd:decls)
> return $ Lazy (App (R newname) (map V (map snd env)))
+> tc env (Par e) =
+> do (maxlen, nextn, decls) <- get
+> let newname = MN (getRoot nm) nextn
+> let newargs = zip (map fst env) (repeat TyAny)
+> let newfn = Bind newargs 0 e []
+> let newd = Decl newname TyAny newfn Nothing []
+> put (maxlen, nextn+1, newd:decls)
+> return $ Par (App (R newname) (map V (map snd env)))
> tc env (Lam n ty e) = lift e [(n,ty)] where
> lift (Lam n ty e) args = lift e ((n,ty):args)
View
@@ -49,6 +49,7 @@ Also consider creating specialised versions of functions?
> _ -> R fn
> s' args d (App f a) = apply d (s' args d f) (map (s' args d) a) args
> s' args d (Lazy e) = Lazy $ s' args d e
+> s' args d (Par e) = Par $ s' args d e
> s' args d (Effect e) = Effect $ s' args d e
> s' args d (While t e) = While (s' args d t) (s' args d e)
> s' args d (WhileAcc t a e) = WhileAcc (s' args d t) (s' args d a) (s' args d e)
@@ -7,7 +7,7 @@ TEXFILES = ${PAPER}.tex intro.tex language.tex example.tex \
DIAGS =
-SOURCES = ${TEXFILES} ${DIAGS} macros.ltx literature.bib
+SOURCES = ${TEXFILES} ${DIAGS} macros.ltx comments.sty library.ltx llncs.cls literature.bib
DITAA = java -jar ~/Downloads/ditaa.jar
@@ -33,4 +33,6 @@ progress: .PHONY
%.png : %.diag
$(DITAA) -o -E $<
+distrib: all
+ cp ${PAPER}.pdf ${SOURCES} tfp9
.PHONY:
@@ -129,7 +129,6 @@ \subsection{Abstract Syntax}
type Proc = ([Id], Turtle)
type Defs = [(Id, Proc)]
-
\end{SaveVerbatim}
\useverb{atuinprog}
@@ -164,7 +163,7 @@ \subsubsection{Compiling Primitives}
\noindent
Correspondingly, we can extract the concrete values safely from this
-structure, checking that the value is the required type, e.g.:
+structure, checking that the value is the required type, e.g.
\begin{SaveVerbatim}{epicgetval}
@@ -178,7 +177,7 @@ \subsubsection{Compiling Primitives}
Similarly, \texttt{getChar}, \texttt{getBool} and \texttt{getCol}
check and extract values of the appropriate type.
Using these, it is simple to define primitive arithmetic operations
-which check they are operating on the correct type, and report an
+which check that they are operating on the correct type, and report an
error if not.
\begin{SaveVerbatim}{primops}
@@ -208,7 +207,7 @@ \subsubsection{Graphics Operations}
\noindent
The \texttt{startSDL} function opens a window with the given
-dimensions, and returns a pointer to a \emph{surface}, on which we can
+dimensions, and returns a pointer to a \emph{surface} on which we can
draw; \texttt{drawLine} draws a line on a surface, between the given
locations, and in the given colour, specified as red, green, blue and
alpha channels.
@@ -263,12 +262,12 @@ \subsubsection{Graphics Operations}
\useverb{drawfwd}
\noindent
-Note that there is a distinction between Epic code fragments, and Epic
-functions. We have used \texttt{getInt}, \texttt{esin} and
-\texttt{ecos} as inline Haskell functions, using Haskell application,
-but \texttt{drawLine} is applied as a separately defined Epic
+Here we have applied \texttt{getInt}, \texttt{esin} and
+\texttt{ecos} as Haskell functions, so they will be inlined in the resulting Epic code.
+In contrast, \texttt{drawLine} is applied as a separately defined Epic
function, using Epic's application operator (\texttt{@@}).
+\vspace*{-1em}
\subsubsection{Compiling Programs}
Programs return an updated turtle state, and possibly perform
@@ -312,14 +311,14 @@ \subsubsection{Compiling Programs}
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
-the state is maintained. For example, to compile a call, we
+the state is maintained. For example, to compile a call we
build an Epic function call and add the current state as the first
argument. Epic takes strings as identifiers, so we use \texttt{fullId
:: Id -> String} to convert an Atuin identifier to an Epic identifier.
\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
@@ -339,19 +338,19 @@ \subsubsection{Compiling Programs}
\useverb{compseq}
Atuin has higher order procedures which accept code blocks as
-arguments. To compile a code block, we simply create a function which
+arguments. To compile a code block, we build a function which
takes the turtle state (that is, the state at the time the block is
-executed, not the state at the time the block is created). Then when
-it is time to evaluate the block, we pass in the current state. Epic's
+executed, not the state at the time the block is created).
+Epic's
\texttt{effect\_} function ensures that a closure is evaluated, but
-the result is not updated as evaluating the closure may have side
+the result is not updated. Evaluating the closure may have side
effects which may need to be executed again --- consider the
\texttt{repeat} function above, for example, where the code block
should be evaluated on each iteration.
\begin{SaveVerbatim}{blockeval}
-compile state (Block t) = lazy_ (\st -> compile st t)
+compile state (Block t) = term (\st -> compile st t)
compile state (Eval e) = effect_ (compile state e @@ state)
\end{SaveVerbatim}
@@ -361,7 +360,7 @@ \subsubsection{Compiling Programs}
The rest of the operations are compiled by a direct mapping to the
primitives defined earlier. Finally, the main program sets up an SDL
surface, creates an initial turtle state, and passes that state to the
-user defined \texttt{main} function:
+user-defined \texttt{main} function:
\begin{SaveVerbatim}{runmain}
@@ -379,6 +378,4 @@ \subsubsection{Compiling Programs}
\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
-with SDL.
+Hackage.
@@ -14,11 +14,20 @@ \section{Related Work}
language as an API to make it as reusable as possible. Although there
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. 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
+build a new compiler quickly.
+%
+As far as we are aware, Epic occupies a unique point in the design space of
+code generation tools --- it is sufficiently high level that it captures common
+functional language abstractions without being so high level that it imposes
+constraints such as a type system on the language it is compiling.
+Alonzo, for example, is a prototype compiler for Agda~\cite{alonzo} which compiles
+via GHC, but requires coercions in the generated code in order for it to be accepted
+by GHC's type checker. Coq's program extraction tool~\cite{extraction-coq}
+also aims to generate executable code via a high level language, similarly requiring
+coercions where Coq terms can not be given a type in the high level language.
+In contrast, systems such as the Lazy Virtual Machine~\cite{lvm},
+C\texttt{--}~\cite{c--} and LLVM~\cite{llvm} are
+designed as lower level target languages rather than high level APIs. We could
nevertheless consider using these tools for Epic code generation.
%C--~\cite{c--} and LLVM~\cite{llvm}
@@ -31,8 +40,9 @@ \section{Conclusion}
experimental languages (e.g. experimenting with new type systems or
domain specific language design) into larger scale, usable tools, by
providing an API for generating a compiler, dealing with
-well-understood but difficult to implement problems such as lambda
-lifting, code generation, interfacing with foreign functions and
+well-understood but difficult to implement problems such as
+naming and scope management,
+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
@@ -65,7 +65,7 @@
system interaction. Although implementation techniques are by now
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
+scratch, or attempting to 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
@@ -89,14 +89,13 @@
\input{conclusions}
-%\vspace{-0.2in}
-%% \section*{Acknowledgments}
+\vspace{-0.2in}
+\section*{Acknowledgments}
-%% This work was partly funded by the Scottish Informatics and Computer
-%% Science Alliance (SICSA) and by EU Framework 7 Project No. 248828
-%% (ADVANCE). I thanks James McKinna, Kevin Hammond and Anil
-%% Madhavapeddy for several helpful discussions, and the anonymous
-%% reviewers for their constructive suggestions.
+This work was partly funded by the Scottish Informatics and Computer
+Science Alliance (SICSA) and by EU Framework 7 Project No. 248828
+(ADVANCE). Thanks to the anonymous
+reviewers for their constructive suggestions.
\bibliographystyle{abbrv}
\begin{small}
Oops, something went wrong.

0 comments on commit d359393

Please sign in to comment.