Skip to content


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

1012 lines (851 sloc) 49.231 kb
%TODO: Add pretty code example
%TODO: Add explanation of how we handle types
%include IdentColors.fmt
%include Javascript.fmt
%format a_1
%format a_i
%format a_j
%format a_n
%format MANY = "\!^{*}"
%format ::= = "::="
%format \ = "{\lambda}"
% defs etc
\def\jqui{jQuery UI\xspace}
We introduce the Utrecht Haskell Compiler JavaScript backend, which allows one
to compile Haskell code to JavaScript, so it can be run in the browser. To
interface with JavaScript and overcome part of the impedance mismatch between
the two languages, we introduce the Foreign Expression Language; a small subset
of JavaScript for use in Foreign Function Interface imports. Finally we discuss
the implementation of a JavaScript application, completely written in Haskell,
with which we show that it is now possible to write an entire JavaScript
application completely in Haskell.
\keywords{Compilation, FFI, Web Applications, Haskell, Javascript}
When developing interactive web applications, JavaScript is often the language
of choice due to native support in every major web browser. In contrast to
other client-side programming languages, no plugins are needed to execute
JavaScript. Unfortunately, JavaScript is currently the \textit{only}
client-side programming language that is supported by all major browsers.
People wishing to use other programming languages or paradigms have to rely on
using existing plugins such as Flash or Java Applets, writing custom browser
plugins, or modifying the browsers themselves. None of these options are ideal,
since they either require a lot of work, or force the use of strict, imperative
programming languages. Instead of choosing between the aforementioned options,
we use the Utrecht Haskell Compiler (UHC)~\cite{dijkstra09uhc-arch,www09uhc} to
compile Haskell code to JavaScript, effectively using JavaScript as a
high-level byte-code, and allowing us to side-step the problems identified with
the other approaches.
In this paper, we introduce the UHC JavaScript backend, a compiler backend that
allows one to compile Haskell to JavaScript, while keeping Haskell's lazy
semantics. We assume at least some familiarity with the Haskell Foreign
Function Interface (FFI) and JavaScript. To overcome the impedance mismatch
between Haskell and JavaScript, we have extended UHC's FFI with a small
JavaScript-like expression language we call the Foreign Expression Language
(FEL). With these enhancements to the FFI, we claim that it is now possible to
write complete JavaScript applications using only Haskell. We back up this
claim by porting a web-based Prolog ``proof assistant'' from JavaScript to
Haskell. While this paper focusses on Haskell, the ideas should be relatively
easy to implement in similar languages. Additionally, we provide a library
containing bindings to the JavaScript standard functionality and bindings to
several other commonly used JavaScript libraries.
With this paper, we make the following contributions:
\item We introduce the UHC JavaScript backend, a compiler backend that allows
one to compile any Haskell code supported by UHC to JavaScript and execute
it in the browser, maintaining Haskell's lazy semantics.
\item We introduce the Foreign Expression Language (FEL), which allows for a
more natural way of interfacing with object-oriented languages via the FFI.
\item We give a realistic example which shows that it is now possible to
write complete JavaScript applications using only Haskell.
\item We provide a basic library with bindings to common JavaScript APIs.
The rest of this paper is structured as follows: Section~\ref{hs2js} introduces
the UHC JavaScript runtime system (RTS). Section~\ref{ffi} covers the FFI with
our additions, after which Section~\ref{jcu} shows how we have implemented a
fully working JavaScript application completely in Haskell.
Sections~\ref{future} and~\ref{related} discuss future and related work
respectively, after which Section~\ref{conclusion} concludes.
\subsection{\label{rts}Runtime System}
There exists an obvious mismatch between Haskell and Object-Oriented (OO)
languages, such as JavaScript, which has been addressed in various ways over
time (Section~\ref{related}):
\item Mapping the runtime machinery required for Haskell to an imperative
language has to deal with the lazy evaluation strategy imposed by Haskell
(rest of this section).
\item Use of OO language mechanisms as available in JavaScript, in particular
prototype based objects, in Haskell; we only mention this topic in passing.
\item Use of available JavaScript libraries; we deal with this in the next
section by exploiting the freedom offered by Haskell's Foreign Function
Interface (FFI)
The design of any backend for a lazy functional language needs to deal with
functions, their (lazy) application to arguments, and reducing such
applications to Weak Head Normal Form (WHNF). The design should also cater for
under- and over saturated function applications as well as tail recursion.
In UHC's JavaScript backend, functions and their applications are both
represented straightforwardly by objects:
Fun.prototype = {
applyN : function ( args ) ...
needsNrArgs : function() ...
function Fun( fun ) { ... }
We omit implementation details and only expose the programmatic interface as
used by the runtime system. The actual implementation can be found in the UHC
Git repository~\cite{uhc-git}. A |Fun| object wraps a JavaScript function so
that it can be used as a Haskell function. The |applyN| field is only used when
function applications are being evaluated (forced); only then it is necessary
to know the |needsNrArgs| number of arguments which must be passed. For the
time being it stays unevaluated as a |Fun| object wrapped inside an |App| or
|AppLT| closure object, which will be explained below.
Similarly, closures stemming from partially applied (and thus undersaturated)
functions need to store already passed arguments and how many arguments are
still missing. An |AppLT| (|LT| stand for \emph{less than}) object encodes this
and again we provide its programmatic interface first:
AppLT.prototype = {
applyN : function ( args ) ...
needsNrArgs : function() ...
function AppLT( fun, args ) { ... }
An |AppLT| only wraps other |AppLT| objects or |Fun| objects.
Finally, for all remaining saturation cases an |App| object is used. Knowledge
about the degree of saturation is delegated to the encapsulated function
object, which may be another |App|, |AppLT|, or |Fun|.
App.prototype = {
applyN : function ( args ) ...
function App( fun, args ) { ... }
With this interface we now can embed Haskell functions; for example, assuming
an elementary JavaScript representation of the Haskell function |id|, the
function |\x -> id ^ (id x)| is available, by:
new Fun( function(x) {
return new App(id, [new App(id,[x])]);
} )
Evaluation is forced by a separate function |eval| which assumes the presence
of an |eOrV| (evaluator Or Value) field in all Haskell runtime values, which
tells us whether the JavaScript object represents a Haskell non-WHNF value
which needs further evaluation or not; in the former case it will be a \js
function of arity 0, which can be called. A Haskell function or application
object does not evaluate itself since the tail recursion involved will cause
the stack of the underlying JavaScript engine to flow over. The separate
external function |eval| doing the evaluation allows non WHNF values to be
returned, thus implementing a trampoline mechanism:
function eval( x ) {
while ( x && x.eOrV ) {
if ( typeof x.eOrV == 'function' ) {
x = x.eOrV^() ;
} else {
x = x.eOrV ;
} }
return x ;
Even normal \js values can be thrown at |eval|, provided they do not
(accidentally) contain an |eOrV| field. The actual |eval|\footnote{called \texttt{\_e\_}
in the implementation.} function is somewhat more involved as it provides some
protection against null values and also updates the |eOrV| field for all
intermediate non WHNF objects computed in the evaluation loop.
As usual, the evaluation is driven by the need to pattern-match on a value,
e.g. as the result of a case expression or by a built-in \js primitive which is
strict in the corresponding argument. As in the wrapper of the primitive
multiplication function, which contains the actual multiplication (|*|):
new Fun( function(a,b) {
return eval(a) * eval(b) ;
} )
Depending on the number of arguments provided, either an undersatured closure
is built, or the function is directly invoked using JavaScript's |apply|. In
case too many arguments are provided, a JavaScript closure is constructed,
which subsequently is evaluated in the evaluation loop of |eval|. The
implementation of |AppLT| is similar to that of |Fun|. |App|'s implementation
of |applyN| simply delegates to |applyN| of the function it applies to. Also
omitted are the encodings of nullary applications, used for unevaluated
constants (CAF, Constant Applicative Form) and indirection nodes required for
mutual recursive definitions. Data types and tuples are straightforwardly
mapped onto JavaScript objects with fields for the constructor tag and its
fields. If available, record field names of the corresponding Haskell data type
are used. We map |Int|, |Double|, |Float|, |Integer|, and |PackedString| values
to \js objects, shown in \tableref{table:typemap}. Despite the mapping to \js
objects, the expressions of these types are lazy.
\begin{tabular}{l l}
\textbf{Haskell} & \textbf{\js}\\
|Int|, |Double|, |Float| & |Number|\\
|Integer| & |BigInt| (non-native, offered by a library)\\
|PackedString| & |String|\\
otherwise & RTS representation\\
\caption{Mapping from Haskell Types to native \js types}
\section{\label{ffi}JavaScript Foreign Function Interface}
We have extended the FFI with the Foreign Expression Language (FEL), a small
JavaScript-like language that greatly simplifies interfacing with the
JavaScript world from Haskell. The FEL allows one to number and reorder the
function arguments, explicitly use them as arguments to JavaScript functions,
or use them as objects. Other features include hardcoding of literals,
accessing array indices, and a built-in mechanism for converting data-types to
JavaScript objects. The new grammar for importing functions is shown in
exp ::= '{}' ^ -- Haskell constructor to JavaScript object
| (arg | ident) post MANY ^ -- JavaScript expression
post ::= '.' ident ^ -- object field
| '[' exp ']' ^ -- array indexing
| '(' args ')' ^ -- function call
args ::= epsilon | arg (, arg) MANY ^ -- possible arguments
arg ::= '%' ('*' | int) ^ -- all arguments, or a specific one
| '"' str '"' ^ -- literal text
ident ::= a valid JavaScript identifier
int ::= any integer
str ::= any string
\caption{Import entity notation for the JavaScript calling convention}
Common FFI features, such as the \emph{dynamic} and
\emph{wrapper}~\cite{Haskell98} imports, work as expected, allowing one to use
higher-order JavaScript functions in the same way as C function pointers.
As an example of how to use the FEL to import a JavaScript function, suppose we
want to import the \texttt{subString} method from the JavaScript String class,
where \texttt{myStr} is a concrete JavaScript string object:
myStr.subString(start, length);
This method is called on a JavaScript string object, and returns a substring,
based on the integer value for a start offset and an integer value for the
length of the substring, both of which are passed as arguments to the method.
Importing this method shows the FEL's added value in several ways: the method
is called on a JavaScript \textit{object}, it takes multiple
\textit{arguments}, and it requires conversion from a Haskell |String| type to
a native JavaScript string type\footnote{Naively using a Haskell |String| would
give us a JavaScript representation of a list of characters, rather than a
JavaScript string. To obtain a native JavaScript string, we require the Haskell
|String| to be converted to a |JSString|, which is a type synonym for
|PackedString|.}. The import is shown below:
foreign import js "%1.subString(%2, %3)"
subString :: JSString -> Int -> Int -> JSString
In addition to the |js| calling convention, the other noticeable difference
with, for example, a C import, is the import definition in the string. Rather
than having the FFI place all arguments in one position, we number the
arguments and allow them to be placed in different positions in the imported
method. The first argument, indicated by \texttt{\%1}, before the dot, is
treated as an object in the generated JavaScript code. The number of the
argument corresponds to the position of the arguments in the type signature.
The two remaining arguments are placed between parentheses, so that they become
arguments in the method call in the generated JavaScript code.
An alternative way of writing this import is shown below, where we replace the
last two explicit argument positions with a wildcard. This says that all
remaining arguments should be placed where the wildcard is. Using a wildcard
has as added advantage that it becomes easy to import variadic methods.
foreign import js "%1.subString(%*)"
subString :: JSString -> Int -> Int -> JSString
Exporting a function does not make use of the FEL, so it is not much different
from exporting a function for the C FFI. The only concerns to keep in mind are
using the |js| calling convention, and specifying a JavaScript-compatible type
in the type signature.
\subsection{\label{uhc-js}The UHC-JavaScript library}
We provide a library~\cite{uhcjs}, simply called the UHC-JavaScript library, to
streamline the development of \js applications with UHC. It contains bindings
to standard ECMAScript~\cite{ecmascript}, the formal standard behind JavaScript,
as well as bindings to the jQuery library~\cite{www11jquery}. The library aims
to provide a bare-metal interface that is consistent with the JavaScript
functions. Eventually, this library should form a core upon which more
(functional) abstractions are built. We shall make use of this library in the
rest of this paper.
\subsection{\label{object-rts}Creating, manipulating and querying objects}
Being a purely functional programming language, Haskell has no notion of
objects. JavaScript, however, does. Objects come in two flavours: anonymous and
named objects. The former is denoted in \js as |{}|, while the latter is
created by defining a constructor function whose name starts with an
uppercase letter, as in |function MyObj() {}|. Objects can then be
instantiated with the |new| keyword: |new MyObj()|. Each function also has a
prototype object. This prototype enables defining values and functions within
the scope of the object. New object instances will automatically have the same
values and functions as the prototype.
%UHC now offers a functional interface for creating, instantiating and
%manipulating objects and prototypes in \js during runtime. We can convert
%datatypes to objects, or we can define objects from scratch.
UHC offers support for creating, manipulating and querying objects, using
several new primitive functions in the runtime-system (RTS). Instead of showing
the rather uninteresting function definitions in JavaScript, the code below
shows the Haskell type signatures which need to be used when importing these
primitives with the FFI:
primMkCtor :: JSString -> IO ()
primMkObj :: JSString -> IO (JSPtr c)
primMkAnonObj :: IO (JSPtr c)
primGetAttr :: JSString -> JSPtr c -> IO a
primSetAttr :: JSString -> a -> JSPtr c -> IO (JSPtr c)
primModAttr :: JSString -> (a -> b) -> JSPtr c -> IO (JSPtr c)
primGetProtoAttr :: JSString -> JSString -> IO a
primSetProtoAttr :: JSString -> a -> JSString -> IO ()
primModProtoAttr :: JSString -> (a -> b) -> JSString -> IO ()
|JSString| is a type synonym for |PackedString|, the builtin type corresponding
to JavaScript strings. The |primMkCtor| function creates a new constructor
function if it does not yet exist in the |window| scope, where |window| is the
variable containing everything pertaining the current window or tab. This
function is usually only called from within the other functions listed above.
The |primMkAnonObj| function creates an anonymous object |{}|, while
|primMkObj| accepts a string with the class name of the object to be created.
If the class does not exist yet, it is created using an empty constructor.
The other functions manipulate objects and prototypes, using a mechanism
inspired by
an abstraction over accessors and mutators. The first argument is always the
name of the object attribute of interest passed as a string. In case of the
|set|-functions, the second argument is the value that needs to be set. Since
\js is a loosely typed language, this can be any type, even when interfacing
with it from the Haskell world. The |mod|-functions take as second argument a
function which modifies the attribute specified in the first argument.
Modifying an attribute may change its type, hence the |a -> b| type for the
function. Finally, the last argument is either a reference to an object, or the
name of a class as a string, in case of prototypes.
These functions can be used by importing them as primitives:
foreign import prim "primGetAttr"
_getAttr :: JSString -> JSPtr p -> IO a
Objects are represented in the UHC-JavaScript library by a |JSPtr| type, which
has no constructors, so they can't be instantiated directly. The only way an
object can be obtained is by getting it via the FFI. A |JSPtr| takes one
phantom type as a parameter, which specifies the type of the \js object. This
should again be a type without constructor. Suppose we want a pointer to a \js
|Book| object, for which we have some definition in \js. We define it in
Haskell as follows:
data BookPtr
type Book = JSPtr BookPtr
We can now define functions on the |Book| type, giving us a type-safe way to
deal with \js objects. A similar approach is often taken in GHC's C FFI to deal
with pointer types.
We offer the |Language.UHC.JS.Primitives| module in the UHC-JavaScript library,
which defines primitive imports and abstracts away from |JSString|. Using these
functions we can now create, manipulate and query an object:
main = do
o <- mkObj "Book"
setAttr "pages" 123 o
modAttr "pages" (+1) o
p <- getAttr "pages" o
print p -- Prints 124
While defining objects as shown in the previous example works fine, the process
is rather verbose and tedious, especially when dealing with several object
attributes. It would therefore be ideal if we could use Haskell datatypes to
achieve the same results. In some ways, datatypes and \js objects have a lot in
common, especially when the datatype has record selectors. Suppose we have a
simple |Book| type\footnote{We use |JSString| here so that the resulting Haskell record
relates more closely to the \js object.} in Haskell:
data Book = Book
{ author :: JSString
, title :: JSString
, pages :: Int }
A concrete |Book| value would look as follows:
myBook = Book
{ author = toJS "me"
, title = toJS "story"
, pages = 123 }
The representation of |myBook| closely resembles an object with the same data
in JavaScript:
myBook =
{ author : "me"
, title : "story"
, pages : 123 }
In fact, a \js object very similar to the one shown above is already being
generated by the UHC. However, since it is generated as an application of
a constructor to some values, the generated datatype values are not directly
usable in other \js libraries. We require a mechanism to convert the Haskell
representation of the datatype into a \js representation. This idea is similar
to that of the FFI's wrapper import feature. Using a similar mechanism to the
wrapper, we can make Haskell datatypes available as \js objects. This mechanism
is exposed via the FEL, simply as |{}|:
foreign import jscript "{}"
mkObj :: a -> IO (JSPtr b)
It takes a datatype |a| and converts it to a plain \js object, resulting in a
pointer to the new object. If the datatype contains record selectors, they will
be used as the object's indices. When no record selectors are available, an
integer is used instead.
Creating the object is achieved by recursively evaluating and cloning the data
inside the datatype to a new, empty object, disposing of RTS-specific
information in the process. Using the object wrapper, we can simplify our
example from before:
main = do
let b' = myBook { pages = pages myBook + 1 }
b <- mkObj b'
p <- getAttr "pages" b
print p -- Prints 124
Note that even though this example is only one line shorter, we also have the
two strings available in our \js object, which would haven taken two more lines
in the original example. More importantly, Haskell's type system is in a much
better position to catch programmer mistakes, since record selectors are used
in the modification of the |pages| value instead of strings.
\subsection{Pure objects}
%TODO: Proper motiviation for this bit. Just getting out of IO is maybe not
% enough as we didn't use it in our JCU application.
Objects in \js are mutable by nature. By modifying an object, you modify it for
everything that has a pointer to that particular object. This forces any update
operation to be defined in |IO|. In order to escape the |IO| monad, update
operations need to become non-destructive, which is achieved by creating a copy
of an object before modifying it. The RTS exports a primitive to do exactly
primClone :: JSPtr a -> JSPtr a
By cloning an object first, all pointers to the original object remain
untouched when modifying the clone. This enables pure variants of the
|primSetAttr| and |primModAttr| functions:
primPureSetAttr :: JSString -> a -> JSPtr c -> JSPtr c
primPureModAttr :: JSString -> (a -> b) -> JSPtr c -> JSPtr c
Since a potentially large tree of objects will be cloned by these pure
functions, they should be used with care. The cloning method used is a
modification of the cloning method used by jQuery~\cite{www11jquery}.
% What does the app do? How is it implemented? Does it work? Does it work well?
% Is the UHC JS backend a full replacement for JS coding? Etc?
% \cite{swierstra2011,stutterheim2012} \cite{snap}
To explore the limitations, and to demonstrate the features of the UHC
JavaScript back-end in a real-life scenario, we ported the `JCU Prolog Proof
Assistant'~\cite{swierstra2011}, a web application developed to aid in
teaching~\cite{stutterheim2012} Prolog at the Junior College Utrecht, to
Haskell. It is a tool developed for students to learn about important concepts
in computer science, such as proofs, trees, unification, and backtracking, by
means of proving Prolog queries manually. Students enter a Prolog query, after
which they can build a proof of this query by dragging and dropping Prolog
rules and facts on top of the query, and by applying substitutions manually
throughout the proof tree.
The application was originally programmed in \coffeescript~\cite{coffeescript},
a layer of syntactic sugar for \js, and used the \brunch~\cite{brunch}
framework. In the original implementation, all Prolog logic was implemented
server-side in Haskell, using the NanoProlog~\cite{nanoprolog-package} library.
We rewrote the application in Haskell using UHC and the UHC-JavaScript library.
We also use jQuery for interacting with the Document Object Model (DOM) and the
jQuery AjaxQueue~\cite{ajaxq} plugin for sequential non-blocking communication
with the server. The resulting application has the same functionality as the
original implementation and appears to be at least as stable, although this has
only been manually tested. As is expected of applications that interact heavily
with a graphical user interface, a large part of the application's code lives
in the |IO| monad.
With the ability to compile Haskell to JavaScript comes the possibility of
running any Haskell library that compiles on UHC in the browser, without
modification. We use this feature in the JCU web application to run the
NanoProlog library in the browser, allowing us to perform proof checking and
unification at the client-side, eliminating the need for many AJAX requests.
In a further step we eliminated the need for a server altogether by storing the
set of rules and facts using HTML5 Local Storage, a browser-based database
supported by most modern browsers, instead of in a database on the server. With
this modification, the assistant can be run with only the requirement of a
modern web browser; no Internet connection is required. A live demo is
available online\footnote{\verb||}.
\subsection{\label{issues}Implementation Issues}
% TODO describe: Which issues do you run into in general when you develop a JS
% app in Haskell?
% Ale: non-termination/threads, no native OO, interfacing with annoyingly
% multi-interpretable functions (functions that are dimensioned in both the number
% and type of their arguments)
% \TODO{Mismatch GHC/UHC with shared modules, some copying done, but should have separated out definitions, points to the issue where UHC is missing some features}
Most of the problems we encountered in porting the JCU application to Haskell
were due to the lack of advanced language features in UHC, such as functional
dependencies and type families. Practically, this implies that only part of the
libraries available on Hackage today can currently be compiled to JavaScript
using the UHC JavaScript back-end.
Another issue arises from JavaScript's scoping rules. In \js, the keyword
|this| is dynamically scoped while all other variables are lexically scoped.
Since we emulate lazy evaluation by native JavaScript functions encapsulated by
objects, the |this| keyword can in some cases point to the runtime system,
rather than the expected scope, exposing the runtime system to the programmer.
Simply importing |this| as a function using the FFI is not an option here.
This might happen when an imported JavaScript library expects the programmer to
make use of the |this| keyword in a callback function. The \jq library, for
example, expects event callbacks to get the active DOM-node using the |this|
keyword. One way to still get a reference to the expected object when using
|this| is to create a wrapper function that captures the expected scope and
passes it to the wrapped function as explicit argument. We have implemented
this solution in the |wrappedThis| function, which is part of our RTS.
% One would be tempted to import the
% keyword as a function as follows:
% \begin{code}
% foreign import js "this"
% this :: IO JQuery
% \end{code}
% However, this would insert the \js |this| keyword inside the \js code that
% represents our Haskell function. This function is then wrapped by our dynamic
% wrapper. Since our function is called by our RTS, the |this| keyword referreds
% to the RTS objects' scope, essentially exposing the RTS to the Haskell world
% and hiding the scope that one would expect to get when we would be using plain
%\js. One way to deal with this problem is by creating a wrapper function that
\figureref{code:this} shows how the |wrappedThis| function can be used to
obtain the value of an HTML input field. The code above the definition of
|bindInput| is copied from the \js library; |valString| is a function that gets
the value of a \jq object as a |String|. We query the DOM using jQuery,
retrieving all \texttt{input} elements, such as text fields, in the DOM. We
define a function |alertHndlr| that takes the string value of a jQuery object
and then shows it in an alert box. Note the explicit |this| parameter. We then
wrap it so it becomes a \js function, after which we partially apply it to an
explicit |this| parameter using |wrappedThis|. Finally, we bind the event
handler to all input fields retrieved by our jQuery selector.
%TODO: Rewrite the bit above?
data JQueryPtr
type JQuery = JSPtr JQueryPtr
type ThisEventHandler = JQuery -> JQuery -> JEventResult
type JEventHandler = JSFunPtr (JQuery -> JEventResult)
type JThisEventHandler = JSFunPtr ThisEventHandler
foreign import js "%1.bind(%*)"
bind :: JQuery -> JSString -> JEventHandler -> IO ()
foreign import js "wrappedThis(%1)"
wrappedThis :: JThisEventHandler -> IO JEventHandler
valString :: JQuery -> IO String
mkJThisEventHandler :: ThisEventHandler -> IO JThisEventHandler
bindInput = do
let alertHndlr :: ThisEventHandler
alertHndlr this _ = valString this >>= alert
inputField <- jQuery "input"
eh <- mkJThisEventHandler alertHndlr >>= wrappedThis
bind inputField (toJS "blur") eh
\caption{Code for adding an event handler to an input field}
A last example of implementation difficulties is found in the lack of threading
support in our current implementation of the proof assistant, and in the
current implementation of the UHC \js backend. In addition to the web-based
proof exerciser, we offer a web-based user interface to NanoProlog's
interpreter. In some cases, the interpreter can get stuck in an infinite
recursion when trying to unify a rule. For example, trying to prove the query
|silly(X)|, where |silly| is defined as |silly(X):-silly(X).|, will never
terminate. Originally, we spawned a new thread on the server, which we would
terminate after a given amount of time. Our current approach, however, does not
yet offer threading, risking blocking the client-side process causing a tab or
the whole browser to hang. JavaScript's WebWorkers might provide a solution to
this problem, although we have yet to investigate this option. Another
solution would be to change the implementation to limit its recursion depth.
% Performance is decent, except for the actual Prolog backtracking. Where is the bottleneck?
% Ale: Probably as I've stated before the problem is in the memory management as
% is supported by the benchmarks in Chrome and Fx.
In general, the performance of the web application is on par with the original
implementation in JavaScript, but only when using a state of the art JavaScript
engine, as is found in Google Chrome or Safari. The largest bottleneck seems to
be memory management. Building up lazy Haskell expressions leads to a large
number of JavaScript objects. The quick creation and then successive
destruction of these large expressions places a strain on the memory manager
and garbage collector. Other popular browsers, such as Firefox, Opera, and
Internet Explorer, perform significantly worse than the aforementioned
browsers, although this has only been tested informally.
While we have shown that it already is possible to implement an entire
JavaScript application in Haskell, there is still a lot of room for
improvement. As mentioned before, UHC itself lacks support for the more
advanced Haskell features, such as type families. Implementing these in UHC
would go a long way to making the UHC JavaScript back-end a true alternative to
Our current UHC-JavaScript library relies on the programmer to use imported
functions correctly. The object-wrapper import, for example, will try to wrap
anything, possibly failing at runtime. Extra constraints could be added,
although the RTS cannot currently deal with them. Eventually, one could imagine
a higher-level library being built on top of the low-level imports to provide
improved type-safety. Such libraries may be based on generic programming to
eliminate repetition, functional reactive
to interact with the DOM, or they may be an entire user-interface toolkit,
such as wxHaskell~\cite{Leijen:2004:WPC:1017472.1017483}.
Working with WebWorkers as a JavaScript counterpart to Haskell threads is
currently not investigated yet. Our JCU application would become significantly
more usable with a threading alternative.
Communication with the server is currently encoded manually. One could imagine
an approach inspired by Cloud Haskell's~\cite{epstein2011} typed channels,
where communication proceeds over type-safe communication channels, abstracting
away from the actual AJAX call.
Currently the only way of converting a datatype to a \js object is to do so at
runtime. This, however, is a process with time complexity linear in the number
of datatype records. Future work could focus on generating (parts of) \js
objects at compile-time, so that only dynamic values will need to be copied to
the object at runtime.
Targeting Haskell to a different platform means that some assumptions following
from using a single platform only are no longer valid. First, a different
platform means a different runtime environment. Almost all of the UNIX
functionality is available for the usual Haskell UNIX runtime, but is naturally
not available inside a web browser and, vice versa, specific JavaScript
libraries like jQuery are not available on a UNIX platform. Some library
modules of a package (partially) cannot be built on some platforms, while
others (partially) can. To cater for this, UHC rather ad-hoc marks modules to
be unavailable for a backend by a pragma \verb|{-# EXCLUDE_IF_TARGET js #-}|.
Of course |CPP| can still be used to select functionality inside a module.
However, in general, awareness of platform permeates all aspects of a language
system, from the compiler itself to the library build system like Cabal. In
particular, Cabal needs a specification mechanism for such variation in target
and platform to allow for selective compilation of a collection of variants.
Currently this means that UHC compilation for the JavaScript backend cannot be
done through Cabal.
Currently, we generate JavaScript from the compiler's core language. It might
be possible to generate faster code which uses native JavaScript language
features when generating JavaScript at a later stage in the compiler pipeline,
where the intermediate code is more imperative in nature.
% \subsection*{Generic |FromJS| and |ToJS| for converting objects/records}
% It should be fairly straightforward to implement a generic implementation for
% |FromJS| and |ToJS| using deriving Generic.
% \subsection*{Providing an api to build web applications}\label{ssec:providing-an-api-to-build-web-applications}
% One could think of providing a similar API such as WxHaskell\cite{wxHaskell}
% does for constructing native application, but for web applications. Also one
% could think of providing a Functional
% Reactive
% interface to building the web application.
% \subsection*{Type checking}
% Currently, foreign expressions are not type checked at all. In case of a
% programming error the compiler will currently panic in the best-case scenario
% and happily generate \js code that fails at runtime in the worst-case scenario.
% Constraints on the imports and exports need to be formalised and the foreign
% types should be type checked according to the foreign expressions. Some example
% constraints that could be type checked:
% \begin{itemize}
% \item Only datatype values may be exported as objects, not functions or
% primitive types.
% \item Only wrapped functions may be exported in objects.
% \end{itemize}
% The first item could be realised by supporting type constraints in the foreign
% import. This is already allowed by the type system, but the RTS does not
% currently support this.
% \subsection*{Testing}
% During development, the code has only received limited, informal testing. The
% UHC's test suite should be expanded to enable automated testing. Additionally,
% real-world \js front-end applications should be ported to Haskell and the
% \uhcjscript library to identify shortcomings of the existing ideas and
% implementations.
% \subsection*{Benchmarking an optimising}
% Some benchmarks have been performed that show that the generated \js is quite
% a bit slower than a hand-written version of the same code. Unfortunately, these
% numbers aren't publicly available, nor is is clear where the biggest
% bottlenecks are located. It would be very interesting to do another round of
% benchmarks, including the object code. Afterwards, it would be interesting to
% identify bottlenecks and find ways to speed up the generated code.
% \subsection*{Safe |this| scope (working title)}\label{future-work:this-scope}
% Is there a way to prevent the RTS from being exposed by using the keyword
% |this|?
% \subsubsection*{Numeric object indices}
% When a datatype without record selectors is converted into a \js object, the
% object's attribute name becomes an integer $\geq{1}$ with an underscore prefix.
% Ideally this would be a numeric index $\geq{0}$.
%JavaScript code is usually downloaded, hence compact representation as well as
%avoiding or delaying loading of code is important. Although UHC allows pruning
%of unused code as to achieve a relative compact representation, it provides no
%mechanism for dynamic loading of modules. This is left for future
%implementation. In addition UHC is able to perform whole program analysis
%further compacting the JavaScript code and producing a single output JavaScript
%\TODO{Code compactification, module loading, whole prog, ...}
%\subsection*{Packages and The Haskell ecosystem}
%\TODO{Mismatch: Cabal does not deal with multiple backend of one compiler.}
%\TODO{Mismatch: Libraries take GHC as standard, not Haskell2010 (or H98).}
%\TODO{Unix based library is useless, basically other OS to run on, what about shared code, ...}
% \subsection*{Type system absence}
% JavaScript has no type system, the absence of which can be dealt with by using
% phantom types in wrapper functions around untyped FFI calls. More problematic
% are for example DOM functions returning objects with a different interface, like
% a DOM element or attribute. A sum type defining all possible result types could
% be used, but data types are not extensible, which might be too limiting in
% practice. Dynamics might be used as result values, but require assistance from
% the runtime system as well as knowledge about types (e.g. in the form of
% |TypeRep|). Existentially quantified data types and classes might be used
% (similar to extensible exceptions \cite{marlow06extensible-exception}), but then
% knowledge about the class system also seeps into the runtime system. Currently
% this has not yet been further addressed.
% %\TODO{Typing the untyped.}
% \subsection*{Compiling to native \js through Silly}
% The current setup translates Haskell to Core code and from there to our
% representation of Core code in \js. This Core code is then interpreted at
% runtime. To possibly gain performance it is interesting to see whether we can
% take the compilation a step further and compile down to
% Grin\cite{boquist96grin-optim} and possibly Silly\TODO{citation needed}. Then
% instead of translating to C we should compile the Grin/Silly code to \js. We
% expect some difficulties because of the lack of direct memory management in \js
% but it should otherwise be rather straightforward.
% \paragraph{Other approaches.}
The idea of running Haskell in a browser is not new. To our knowledge, the first
attempts to do so using JavaScript were made in the context of the York Haskell
Compiler (YHC)~\cite{www07yhc-javascript}. The DOM
inside a browser was accessed via wrapper code generated from HTML standard
definitions~\cite{www07haskell-in-browser}. However, YHC is no longer
maintained, and direct interfacing to the DOM nowadays is replaced by libraries
built on top of the multiple DOM variations.
GHCJS~\cite{www11ghcjs-git,www12ghcjs-new} is an attempt to use the GHC API to
create a dedicated Haskell to JavaScript compiler. It uses the C calling
convention, rather than a dedicated |js| calling convention. A major advantage
of using the GHC API is that a mature, production-ready compiler, with support
for advanced type-system features is at the programmer's disposal, solving some
of the issues we are currently experiencing due to lack of these
features in UHC. Currently, GHCJS does not support an import system like the
one described in this paper, so its ability to use external APIs is limited.
GHCJS' authors remarked that adding an FEL-like import mechanism to GHCJS
should be relatively straight-forward.
A very recent, and very promising looking attempt at compiling Haskell to
JavaScript is the Fay language~\cite{fay-lang} by Chris Doner, which aims to
support a subset of Haskell and compile to JavaScript. It, too, makes extensive
use of GHC, giving it a production-ready Haskell compiler and type-checker to
build on. In designing Fay's FFI, Doner drew some inspiration from the work we
present here, namely the FEL.
Another recent attempt is Haste\cite{ekblad2012} by Anton Ekblad. It, too,
builds on top of GHC, and it attempts to be easy to use and generate
``relatively lean code''. It comes with a small reactive library for
interacting with the DOM.
Rather than focusing on source-to-source compiling, ``Functional
JavaScript''~\cite{www07functional-javascript} offers a library for a more
functional style of programming in JavaScript. ``Haskell in
JavaScript''~\cite{www10haskellinjavascript} offers an interpreter for Haskell,
written in JavaScript.
The workflow framework |iTasks|, built on top of the Clean
system~\cite{www11clean-system}, uses a minimal platform-independent functional
language, SAPL, which is interpreted in the browser by code written in Java.
The latest interpreter incarnations are written in
Although currently a Haskell front-end exists for Clean, the use of it in a
browser appears to be limited to the iTasks system. The intermediate language
SAPL also does not provide the facilities as provided by our Haskell FFI.
%\subsection{Object orientation.}
%Object Oriented behaviour itself can be realised inside Haskell by exploiting
%the class system \cite{shields01haskell-oo-overloading,kiselyov05haskell-oo}.
%However, we aim to access libraries written in JavaScript, not \emph{mimic}
%JavaScript or OO mechanism in general inside Haskell.
%% TODO: sounds shaky en niet meer helemaal waar voor ons ding?
%However, when functionality of the libraries would have to be (re)written in
%Haskell some form of OO mechanism should be available. This issue arises when
%one would code in Haskell a platform independent part of an otherwise OO GUI
%library, say |wxHaskell|. For now we limit ourselves to accessing JavaScript
%libraries via the FFI, hiding OO idiom inside FFI import entities.
%\TODO{Mapping to OO: FFI or other mechanism.}
%\TODO{Records in JS vs HS.}
% \paragraph{Side effects.}
% All access to JavaScript values is done in the IO monad, so side effect can be properly modelled.
% For now it is assumed that no threads exist.
% Since JavaScript's worker thread mechanism can be used safely we currently do not need
% semaphores, STM, or other shared data access machinery.
% Some values like the globally available @window@ in a browser could be accessed without the use of the IO monad because its value does not change.
% However, if and when this assumption would not hold in a near future it would break our wrapping code as well.
%\TODO{All in IO, what can be done without IO, threads? STM?.}
%\TODO{Onderstaande twee paragrafen zijn een beetje bloat maar er zit misschien nog wel wat in voor later.}
% \paragraph{Mapping to OO runtime environments.}
% In general, it is attractive to map onto available virtual machines for popular OO languages,
% in particular because of the availability of a wealth of libraries.
% Targeting the Java virtual machine (JVM) has been experimented with
% \cite{wakeling98haskell-to-java,func:lazy:java:parser-combinator,stewart02mthesis-multiparadigm-jit,tullsen96haskell-to-java},
% as well as with the @.NET@ platform \cite{monteiro05functional-to-dotnet,www04haskell-dotnet,meijer07mondrian,meijer01dotnet-scripting-mondrian};
% UHC also provides a backend to the JVM \cite{func:lazy:java:parser-combinator}
% using the same technique as described here.
% However, interfacing to libraries is still lacking in UHC, and in general library access and other
% runtime oriented features (threads, exceptions)
% is where the real work lies \cite{www12ghc-faq}.
% Wrapping and interfacing to libraries has to be done manually or by tools interpreting library code which requires substantial effort and is
% suffering from misinterpretation.
% In the case of JavaScript lack of typing annotations even precludes automatic FFI wrapper generation,
% unless type annotations in comments could be trustworthy and formal enough to be used instead.
% Efficient code generation is also an issue.
% Usually non standard OO language constructs are used to implement
% standard idiom of (lazy) functions.
% For now, with UHC we have taken the approach to first make it work and not bother about efficiency,
% generating code from an early stage in the compiler pipeline.
% We expect exploitation of the results of a strictness analyser to speed up the code considerably,
% especially because the existing JavaScript compilers to be better able to analyse the provided code.
\section{More information and download}
For the variant of the JCU application as implemented for this paper more info
(download, how to install, etc) is available, via the UHC www
site~\cite{www09uhc} or directly~\cite{www12uhc-js-backend}.
We have shown that UHC is capable of supporting the development of complete
client-side web applications, opening the door to Haskell-only web development.
In the process we added the FEL to UHC and provided a library that exposes the
\js world to Haskell. Considering the increasing maturity of the GHC-based
solutions, we can conclude that the two biggest contributions of this paper are
the FEL, and our experimental example that writing a complete, non-trivial web
application, optionally using external JavaScript libraries is now possible in
Haskell. Since UHC does not support advanced Haskell language features, and
GHC's development is faster and more consistent, it remains to be seen whether
our implementation in UHC can grow to become a mature tool for developing
JavaScript applications. While still keeping this option open, we also call on
authors of GHC-based solutions to consider using the contributions of this
paper in their work.
When it comes to libraries for writing JavaScript applications in Haskell,
better abstractions are still required to reduce the amount of code that lives
in the |IO| monad directly, and to give programming with the UHC JavaScript
backend a more functional feel. While performance, in most cases, is
acceptable, it needs to be improved if computationally heavy functions are to
be run on the client. In order for most of the frequently used Hackage
libraries to be run on the client, additional work on UHC and Cabal will have
to be performed.
Jump to Line
Something went wrong with that request. Please try again.