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 |