Latest revision as of 14:23, 26 January 2010

GHC's term rewriting engine provides a playground for all sorts of user-defined optimisations and
tweaks to Haskell code.
This page collects examples of the use of rewrite rules.
There is more information available on the GHC rewrite rules page.

As can be seen here, rewrite rules let you teach the compiler about
interesting algebraic properties you code satisfies, that it can't find
on its own.

Note: In general it's a bad idea for rules to change the semantics (meaning) of your code in such a way. Consider someone using reverse . reverse to demand strictness of an IO action, this code would no longer work with the above rule.

Another technique is to use rewrite rules to remove intermediate lists
when building bytestrings from literal string constants. The problem is
that string constants must be converted from a [Char] to a ByteString,
to use literal strings as ByteStrings. This is highly inefficient, when
GHC already allocates string constants as unboxed byte arrays. We can
bypass the [Char] conversion using rewrite rules.

Now, the string literal has been packed by GHC for us into a Addr#, pointing
to a proper C string. Now, we'd like to remove that intermediate
unpackCString#, and just pack the string literal straight into a ByteString,
avoiding an intermediate list.

Rewrite rules can almost be used to solve the infamous 'fromJust: Nothing'
error message. Couldn't we just use rewrite rules to rewrite *transparently
all uses of fromJust to safeFromJust, tagging the call site with a location?
To work this requires a few things to go right:

Now, this approach is a little fragile. 'assert' is only respected by GHC if -O
is not on, so if we happened to try this trick with -O, we'd get:

$ ./A
A: Debug.Trace.Location.failure

So lesson one: you have to do the bug hunting with -Onot.

Currently there's -fignore-asserts for turning off assertions, but no flag for
turning them on with -O, Simon, could this be fixed? Could we get a
-frespect-asserts that works even with -O ?

Ok, assuming this assert trick is used, can we get the compiler to insert the
asserts for us? If so, this would be a great advantage, you'd just be able to
switch on a flag, or import a debugging module, and your fromJusts would be
transparently rewritten. With rewrite rules we do just this!

Looks good! But that is deceiving: the assert was expanded before the rule
fired, and refers to the rewrite rule source line (line 19), not the fromJust
call site (line 12). Now if we could just have the 'assert' token inserted
into the AST before it was expanded, we'd be home and dry. Could this be done
with TH? Or could we arrange for asserts in rewrite rules not to be expanded
till later?

Note that this is still a useful technique, we can rewrite head/fromJust/... to
some other possibly more useful message. And if we can constrain the rule to fire
in only particular modules, we may be able to narrow down the bug, just by
turning on a rule. For example, adding:

By far the most elaborate use of compiler rewrite rules is to perform
automatic deforestation of intermediate data structures. This is
documented in a number of research papers.
Note that also for this application field of rewrite rules the above mentioned problem of potentially changing the semantics of programs occurs. Read further under correctness of short cut fusion.

I like to demonstrate to people, that GHC has already built-in a kind of Computer Algebra system.
The optimizer can be abused to differentiate expressions symbolically.
Unfortunately it cannot be forced to do so.
That's why, some, better say: too many, expressions are not derived.