[Template-haskell] program transformation

Ganesh Sittampalam Ganesh.Sittampalam at comlab.ox.ac.uk
Fri Sep 12 18:10:12 EDT 2003

I'm currently investigating the possibility of redoing MAG in Template
Haskell. MAG is essentially (at least for the purposes of this email) a
system that takes a source program and a bunch of rewrite rules, and
applies the rewrite rules to the program.

I'd like to be able to do this in TH with as little syntactic noise for
the user as possible. The general idea (at the moment) would be to put the
original program within [d| |] brackets, the set of rewrite rules within
[| |] brackets, run a function on the two and splice in the result.

It's not the main purpose of this email, but I should mention that being
able to splice in code in the same module as it is defined would be very
useful for this application, since otherwise any module that makes use of
this will need to be split into two.

There was a previous discussion about TH and Hydra at
which ended up with the idea of using [d| |] brackets for code that was to
be transformed. The extra twist for me is that I have this set of rewrite
rules that I also want to use quasi-quotes for.

A simplified example of a rewrite rule that uses the associativity of (++)
is as follows:

\xs ys zs -> (xs ++ ys) ++ zs ==> xs ++ (ys ++ zs)

==> is an operator of type a -> a -> RewriteRule, so GHC will check for me
that the rewrite rule is type correct. The lambda binding for xs, ys and
zs specifies that the rewrite rule works for any value of them, and also
keeps the compiler happy that I haven't used undefined variables. Of
course, I'm never intending to actually run this code, I'll just use the
result of quasi-quoting it to apply transformations.

Anyway, this all works fine. Now, let's suppose that my original program
defines the function reverse (hiding the Prelude reverse function), and I
want to write a rewrite rule mentioning reverse too. I end up with
something like this:

reversecode =
     reverse [] = []
     reverse (x:xs) = reverse xs ++ [x]

rules = [| [ reverse [] ==> [] ] |]

The second definition won't compile, since reverse isn't in scope
anywhere. I'm trying to work out a good solution to this problem; so far
I've come up with the following ideas:

(a) Merge the rewrite rules and the declarations. E.g:
     let reverse [] = []
         reverse (x:xs) = reverse xs ++ [x]
     in [ reverse [] ==> []
  Pros: - this should actually work for me right now (not actually tested
        - though)
  Cons: - it violates the nice separation between code and transformation,
        - it doesn't read nicely for the user; in particular it'll be
          unpleasant for them to take some existing code and decide to use
          MAG on it

(b) Use a lambda-abstraction or let-binding to make "reverse" appear to be
  Pros: - again this ought to work right now
  Cons: - unless I textually duplicate code, it won't be properly type-checked
        - the renamer will rename "reverse" and I'll have to make some
          nasty assumptions about how that works to get back to the
          original form

(c) Turn the rewrite rules into a separate [d| |] block, and splice in
$(reversecode) at the beginning
  Pros: - Not nearly as inelegant/nasty as (a) or (b)
  Cons: - I still have to search the declaration list for the rewrite
        - This will fall foul of the (second) bug I reported yesterday

(d) Say something like let $(reversecode) in reverse [] ==> []
  Pros: - Seems even less nasty than the above options
  Cons: - disallowed by design in TH, for good reasons; it destroys the
          ability to see where things are bound statically

I'd appreciate any comments or alternative suggestions. Ideally I think
I'm looking for some nice concise way to say that the rewrite rules
quasi-quotes should be parsed and type-checked in the context of the
declarations in original code quasi-quotes.



More information about the template-haskell mailing list