Skip to content
Fetching contributors…
Cannot retrieve contributors at this time
941 lines (790 sloc) 43.3 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 (UHC) JavaScript backend; a compiler
backend which allows one to cross-compile Haskell 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 (FFI) imports. Finally we discuss the implementation of a JavaScript
application, completely in Haskell, with which we show that it is now possible
to develop JavaScript applications completely in Haskell.
When developing interactive web applications, JavaScript is often the language
of choice, due to every major browser supporting it natively. 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 on 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 hacking the browsers themselves. None of these options are ideal,
since they either require a lot of work, or force the use of strict, imperative
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 turning JavaScript into a high-level
byte-code of some sorts.
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 with 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
this claim up 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 the 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 show 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) and FFI with our addition, after which
section~\ref{jcu} shows the implementation of a complete JavaScript application
in Haskell, after which sections~\ref{future} and~\ref{related} discuss future
and related work respectively. Finally, section~\ref{conclusion} concludes.
\subsection{\label{rts}Runtime System}
There exists an obvious mismatch between Haskell and Object-Oriented (OO)
languages, which has been addressed in various ways over time
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
Use of OO language mechanisms as available in JavaScript, in particular
prototype based objects; we only mention this topic in passing.
Use of available JavaScript libraries; we deal with this in the next section
by exploiting the freedom offered by Haskell's Foreign Function Interface
The design of any backend for a lazy functional languages needs to deal with
functions, their (lazy) application to arguments, and evaluating 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.
Similarly, 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 the function |\x -> id ^ (id x)| is,
assuming an elementary JavaScript function |id| 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 entailed tail recursion 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| 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 such 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 JavaScripts |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|, and |Integer| to \js object. See table
\ref{table:typemap} for specifics. All other datatypes are represented by the
structure as explained above. Despite the mapping to \js objects expressions of
type |Int|, |Double|, |Float|, and |Integer| are lazy.
\begin{tabular}{l l}
\textbf{Haskell} & \textbf{\js}\\
|Int|, |Double|, |Float| & |Number|\\
|Integer| & |BigInt|\\
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
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. Functions in these objects can be called in the FEL by using the dot,
just like in JavaScript. 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 figure
\ref{jsimpent}. Common FFI features, such as the \emph{dynamic} and
\emph{wrapper}\cite{Haskell98} imports, work as expected, allowing one to deal
with higher-order JavaScript functions.
exp ::= '{}' ^ -- Haskell constructor to JS object
| (arg | ident) post MANY ^ -- JS 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 JS calling convention}
% TODO: Add example of imports and exports using the FEL
\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 the basis on 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 of which the name starts with an
uppercase letter, like so: |function MyObj() {}|. Objects can then be
instantiated with the |new| keyword: |new MyObj()|. Each function also has a
prototype object. This prototype allows for defining values and functions
within the object scope. 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 now 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 -> 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 -> a
primSetProtoAttr :: JSString -> a -> JSString -> IO ()
primModProtoAttr :: JSString -> (a -> b) -> JSString -> IO ()
|JSString| is a type synonym for |PackedString|, which is used as the type for
JavaScript strings. The |primMkCtor| function creates a new constructor
function if it does not yet exist in the |window| scope. This function is
usually only called from within the other functions listed above. The
|primMkAnonObj| function creates an anonymous object |{}|, while the
|primMkObj| accepts a string with the class name of the new object. 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 in the shape of 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
parameter a function which modifies the attribute specified in the first
argument. Modifying an attribute can cause it to be of a different 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 in the form of 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 libraryl by a |JSPtr a| type,
which has no constructors, so it can't be instantiated directly. The only way
an object can be obtained is by getting it via the FFI. A |JSPtr a| requires
one type argument, which specifies the type of the \js object. This should
again be a type without constructor. Suppose we want a pointer to a |Book|
object, we could define it as follows:
data JSPtr a
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. This is similar approach as 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 in Haskell:
data Book
= Book
{ author :: JSString
, title :: JSString
, pages :: Int
A concrete |Book| value would look as follows:
= Book
{ author = toJS "me"
, title = toJS "story"
, pages = 123
The representation of |myBook| closely resembles an object with the same data
in JavaScript:
{ 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 de 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}
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 just this:
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. 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 are tasked with constructing a proof by dragging and dropping Prolog rules
and facts, 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 the UHC and the UHC-JavaScript
library. We also use jQuery for interacting with the 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 the 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 client-side, eliminating the need for many AJAX requests.
\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, amongst others. 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 then.
A common use-case of when this might happen is 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
Figure \ref{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
foreign import js "%1.bind(%*)"
bind :: JQuery -> JSString -> JEventHandler -> IO ()
type ThisEventHandler = JQuery -> JQuery -> JEventResult
type JEventHandler = JSFunPtr (JQuery -> JEventResult)
type JThisEventHandler = JSFunPtr ThisEventHandler
valString :: JQuery -> IO String
mkJThisEventHandler :: ThisEventHandler -> IO JThisEventHandler
foreign import js "wrappedThis(%1)"
wrappedThis :: JThisEventHandler -> IO JEventHandler
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. 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 proof 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 it's 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 biggest bottleneck seems to
be memory management. Building up lazy Haskell expressions leads to a large
amount 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, the UHC itself lacks support for the more
advanced Haskell features. Implementing these in the UHC would go a long way to
making the UHC JavaScript back-end a true alternative to JavaScript.
Our current UHC-JavaScript library relies on the programmer to use imported
functions correctly. The object-wrapper import, for example, will currently try
to wrap anything, possibly failing at runtime. Extra constraints could be
added, although the RTS cannot currently deal with them. Eventually, one could
image 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, function reactive
to interact with the DOM, or they may be an entire user-interface toolkit, such
as wxHaskell\cite{wxHaskell}.
Working with WebWorkers as an alternative 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, possibly using
existing libraries, like jQuery. 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
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 verse, specific JavaScript
libraries like jQuery are not available on a UNIX platform. Some library modules
of a package (partially) cannot be build 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|.
A second aspect has more to do with the evolution of Haskell as an ecosystem.
Many libraries go far beyond the Haskell standard by making use of GHC
extensions. Currently, such libraries evolve to use type families, a feature not
yet available in UHC. For (non GHC) Haskell compiler writers to keep with this
pace of evolution poses a considerable challenge; yet in our opinion there is
value in the availability of compiler alternatives as well as variation in what
those compilers are good at.
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.
% TODO: Include Fay
% \paragraph{Other approaches.}
The idea of running Haskell in a browser is not new. To our knowledge first
attempts to do so using JavaScript were done in the context of the York Haskell
Compiler (YHC) \cite{www07yhc-javascript}. The Document Object Model (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.
The idea of running functional programs in a browser even goes further back to
the availability of Java applets. 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 seems to be tied up to the iTasks system. The intermediate language
SAPL also does not provide the facilities as provided by our Haskell FFI.
%This limits used code to that which is generated by the iTasks system.
Of the GHC a version exists which generates JavaScript \cite{www11ghcjs-git},
based on the GHC API, supporting the use of primitives but not the FFI.
Further down we elaborate on some consequences of multiple platforms and
backends relevant for this GHC backend variant as well.
Both ``Functional javascript'' \cite{www07functional-javascript} and ``Haskell
in Javascript'' \cite{www10haskellinjavascript} do not use a separate Haskell
compiler. Instead, JavaScript is used directly in a functional style,
respectively a small compiler for a subset of Haskell has been written in
A more recent attempt at cross-compiling Haskell to JavaScript it the Fay
language\cite{fay-lang}, which aims to support a subset of Haskell. It shows
promise, and even draws some inspiration from the work we present here, namely
the FEL.
%\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 the UHC is capable of supporting the development of complete
client-side web applications. This opens 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.
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 in most cases performance 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, UHC and Cabal will need some more work as well.
Something went wrong with that request. Please try again.