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 |