[GHC] #16176: Let-insertion for template haskell
GHC
ghc-devs at haskell.org
Mon Jan 14 10:56:32 UTC 2019
#16176: Let-insertion for template haskell
-------------------------------------+-------------------------------------
Reporter: mpickering | Owner: (none)
Type: feature | Status: new
request |
Priority: normal | Milestone:
Component: Template | Version: 8.6.3
Haskell |
Keywords: | Operating System: Unknown/Multiple
TypedTemplateHaskell |
Architecture: | Type of failure: None/Unknown
Unknown/Multiple |
Test Case: | Blocked By:
Blocking: | Related Tickets:
Differential Rev(s): | Wiki Page:
-------------------------------------+-------------------------------------
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.
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/16176>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list