Opened 6 years ago

Last modified 13 months ago

#1800 new feature request

Template Haskell support for running functions defined in the same module

Reported by: simonpj Owned by:
Priority: normal Milestone:
Component: Template Haskell Version: 7.7
Keywords: Cc: alfonso.acosta@…, Deewiant, reiner.pope@…, eir@…, hackage.haskell.org@…
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: None/Unknown Difficulty: Unknown
Test Case: Blocked By:
Blocking: Related Tickets:

Description

Currently TH has the following restriction:

You can only run a function at compile time if it is imported from another module. That is, you can't define a function in a module, and call it from within a splice in the same module.

This is a pain. It should be fixed.

See http://www.haskell.org/pipermail/template-haskell/2007-October/000619.html, for example.

Change History (12)

comment:1 follow-up: Changed 6 years ago by simonpj

  • Component changed from Compiler to Template Haskell
  • Milestone set to _|_

Here's why it's hard. It involves compiling the functions before the splice to bytecode, so that they can be run. But we don't always want to do that! Usually we do not run any of these functions, and we want to compile them to object code. I don't think it's acceptable to always compile everything to bytecode, just in case.

So the trickiness is simply the plumbing required to notice that f is called from inside a splice, so we'd better compile it to bytecode early. Oh, and the transitive closure of things called by f.

A possible approximation is: see if anything defined in this module is called from within a splice, and if so compile everything to bytecode, just in case.

comment:2 Changed 6 years ago by guest

It would be interesting to note how the template-haskell end user copes with this problem to illustrate why the proposed feature is useful.

I myself have had to face this problem when designing an embedded compiler for system design.
Doe to the mentioned limitation I'm normally forced to "push" the arguments out of the splice.

As a (simplified) example, in my System Modelling DSL I have to create system definition. That is done by providing the function Name together with the identifiers of its inputs and outputs.

inputs = ["in1", "in2"]

outputs = ["out1", "out2"]

f :: Signal Int -> Signal Int -> (Signal Int, Signal Int)
f = ...

Since it is not possible to do

system :: SysDef
system = $(mkSysDef 'f inputs outputs)

due to the limitation explained in this ticket. I'm forced to do:

system :: SysDef
system = $(mkSysDef 'f) inputs outputs

-- where mkSysDef :: Name -> ExpQ

My solution does not solve the problem. It rather bypasses it.

Furthermore, mkSysDef unfortunately cannot do static checking (for
example, it cannot make sure that all the inputs and outputs have
different identifiers). However, that's better than asking the user to
create the system definitions and identifiers in different modules.

comment:3 Changed 6 years ago by guest

  • Cc alfonso.acosta@… added

comment:4 in reply to: ↑ 1 ; follow-up: Changed 6 years ago by fons

Replying to simonpj:

Here's why it's hard. It involves compiling the functions before the splice to bytecode, so that they can be run. But we don't always want to do that!

Due to the additional overhead I presume...

So the trickiness is simply the plumbing required to notice that f is called from inside a splice, so we'd better compile it to bytecode early. Oh, and the transitive closure of things called by f.

I'm not an GHC-expert at all, but, at the risk of not understanding a single word of your answer, can I ask why would it be so difficult to obtain the dependencies of each splice?

A possible approximation is: see if anything defined in this module is called from within a splice, and if so compile everything to bytecode, just in case.

Others might not agree, but at least for me, the lack of the feature requested in this ticket is the biggest practical limitation of Template Haskell.

I ignore what overhead can cause the approximation proposed above, but It would maybe be a good idea to implement it until a better solution is found. Depending on the extend in which compilation-speed is affected, it would even be a good idea to only provide this feature through a compiler-flag.

comment:5 in reply to: ↑ 4 Changed 6 years ago by simonpj

Replying to fons:

Others might not agree, but at least for me, the lack of the feature requested in this ticket is the biggest practical limitation of Template Haskell.

I rather agree -- that's why I created the ticket. But, even with a brutal compile-everything approach it's not straightforward to implement this feature. At the moment there is no plumbing to feed stuff right through the code generator before type checking is complete. Monomorphism makes it more complicated: consider

n = 45 + 23
...
x = n + 1 ::Int

Today, n's (monomorphic) type is resolved to Int, but only at the end of the module; until then we can't generate code for it.

Nothing really difficult, but these tiresome interactions take time to think through and resolve.

Meanwhile, folks, if you care about this feature, add yourselves to the cc list.

Simon

comment:6 Changed 6 years ago by simonmar

  • Architecture changed from Unknown to Unknown/Multiple

comment:7 Changed 6 years ago by simonmar

  • Operating System changed from Unknown to Unknown/Multiple

comment:8 Changed 5 years ago by Deewiant

  • Cc Deewiant added

comment:9 Changed 3 years ago by reinerp

  • Cc reiner.pope@… added
  • Type of failure set to None/Unknown

comment:10 Changed 15 months ago by morabbin

Bump; any recent progress change the landscape here?

comment:11 Changed 15 months ago by goldfire

  • Cc eir@… added

comment:12 Changed 13 months ago by liyang

  • Cc hackage.haskell.org@… added
  • Version changed from 6.6.1 to 7.7
Note: See TracTickets for help on using tickets.