Jhc

Jhc

Jhc is a compiler for Haskell that aims to produce very efficient code as well as explore novel compilation techniques in an attempt to make them practical.

One thing jhc does not aim to be is a toy or proof-of-concept compiler. A lot of the techniques have already had proof-of-concept implementations and jhc aims to determine how to bring them to a full-scale Haskell compiler. (or die trying)

Although jhc is not ready for general use, I think some of its ideas or code might be useful to other people so I am deciding to release it in this state.

Jhc Bullet Points

More in depth

Type Classes

One of the most novel things about jhc is its implementation of type classes which differs significantly from the standard dictionary passing approach used by other Haskell compilers.

Jhc's unique approach is made possible by 2 other design choices, the use of a pure type system with no distinction between types and values and its use of whole-program analysis. The basic idea is that instead of passing a dictionary, a case statement directly scrutinizes the type parameter of a function and calls the appropriate overloaded routine directly.

This has a number of interesting properties

E

E is a pure type system based on Henk and the lambda-cube. An important property of E is that there is no distinction between types and values, this is important for jhc's implementation of type classes.

Grin

Grin is basically a first-order monadic functional language. It is very similar to the Graph Reduction Intermediate Language as defined by Boquist but has a few notable changes.

Most of the transformations mentioned in Boquist's thesis have been implemented, however certain intermediate states in Boquist's scheme are actually invalid in the strongly typed Grin of jhc so need to be combined or modified.

A whole lot can be learned from the Grin data type and Grin is fully defined by the following

infixr 1  :->, :>>=

data Lam = Val :-> Exp
   deriving(Eq,Ord,Show)

data Exp =
    Exp :>>= !Lam
   | App Atom [Val]  -- ^ this handles applications of functions and built-ins
   | Prim Primitive [Val]
   | Case Val [Lam]
   | Return { expValue :: Val }
   | Store { expValue :: Val }
   | Fetch { expAddress :: Val }
   | Update { expAddress :: Val, expValue :: Val }
   | Error String Ty -- ^ abort with an error message, non recoverably.
   | Cast Val Ty     -- ^ reinterpret Val as a different type, also used to box\/unbox lifted types
   deriving(Eq,Show,Ord)

data Val =
   NodeC !Tag [Val]
   | NodeV !Var [Val]
   | Tag !Tag
   | Const Val         -- ^ pointer to constant data, only Lit, Tag, and NodeC may be children
   | Lit !Number Ty
   | Var !Var Ty
   | Tup [Val]
   | ValPrim APrim
   deriving(Eq,Show,Ord)

data Ty =
   TyTag           -- ^ a lone tag
   | TyPtr Ty      -- ^ pointer to a heap location which contains its argument
   | TyNode        -- ^ a whole tagged node
   | Ty Atom       -- ^ a basic type
   | TyTup [Ty]    -- ^ unboxed list of values
   | TyUnknown     -- ^ an unknown possibly undefined type, All of these must be eliminated by code generation
   deriving(Eq,Ord)

Extensions

Jhc implements several extensions to Haskell 98

Standard Extensions

New Extensions

The story of jhc

When I first started to learn Haskell in 1999, I decided I needed a project. Haskell was my first (modern) functional language and I was seduced by its robust strong type system and efficiency gains. After writing a toy ray-tracer (my usual first project in a new language) it was clear I needed to try something somewhat more challenging and jhc was born. My reasoning was simple, by writing a Haskell compiler in Haskell I will double my language learning speed since I will not only have to learn how to program in it by forcing myself to complete a non-trivial project, but also its subtle semantics and dark corners since I actually needed to implement it correctly. Writing a compiler is also doubly efficient to begin with, since if you self-compile improvements not only give you a better optimizer, but also speed up your self-compiled compiler. All in all I figure I was making very good use of my time. For some reason, when I explain my reasoning to other people they look at me like I am crazy, but I can detect no flaw in my logic.

In any case, I worked on jhc on and off for a while, the project got boosts a few times, such as when hatchet was released and I used it to replace my front end.

Recently, with my purchase of a faster machine actually beefy enough to run jhc and the realization I was getting good optimizations from my implementation of type classes combined with the small binary size of produced files I decided to make a push for jhc to become a usable compiler.

All is not well in jhc-land

There are still substantial issues which need to be overcome before jhc can be used for general Haskell programing

References


http://repetae.net/john/computer/jhc


My homepage -> computer stuff -> jhc