Skip to content

Let-insertion for template haskell

When using Template Haskell to generate programs it's very easy to end up with a lot of duplication as splices are naively spliced in place.

For example

foo x = [|| $$x + $$x ||]

Will generate a program which completely duplicates its argument. In this case I can manually remove the duplicate by inserting a let.

foo x = [|| let x' = $$x in x' + x' ||]

Not too bad but a bit annoying to have to do manually.

When constructing bigger programs however this process becomes tedious or impossible to do correctly by hand.

foo :: (Q (TExp (Bool)) -> Q (TExp Int)) -> Q (TExp Int) 
foo xf = [|| (let x = True in $$(xf [|| x ||])) + (let x = False in $$(xf [|| x ||]) ||]

Now if I pass a constant function to foo, the resulting code won't mention x so it could be floated out. However, there's not way I can tell that without running xf so I can't perform the same transformation as I did for the earlier program and manually insert a let. In the case of splicing in fully static data you really want it to float to the top-level and turn into a CAF.

The proposal of this ticket is to implement something like the mechanism for let-insertion in metaocaml.

http://okmij.org/ftp/meta-programming/#let-insert

We add two new primitives:

genlet :: Q (TExp a) -> Q (TExp a)
let_locus :: Q (TExp a) -> Q (TExp a)

genlet marks a code value that we want to float. let_locus marks places where we want to insert a let. When we evaluate the code fragment and encounter a genlet call, whatever the argument evaluates to is floated as far upwards as possible and inserted at the position of one of the loci.

For example,

sqr :: Code Int -> Code Int
sqr c = [|| $$c + $$c ||]

sqr_let :: Code Int -> Code Int
sqr_let c = let_locus (sqr (genlet c))

Splicing sqr [|| 1 ||] will result in 1 + 1 but sqr_let [|| c ||] will equal let x = 1 in x + x ||].

It's important to do this earlier rather than later as a lot of duplication can take place which the simplifier does not like.

Trac metadata
Trac field Value
Version 8.6.3
Type FeatureRequest
TypeOfFailure OtherFailure
Priority normal
Resolution Unresolved
Component Template Haskell
Test case
Differential revisions
BlockedBy
Related
Blocking
CC
Operating system
Architecture
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information