Template PureScript?

Is there any interest in adding compile time metaprogramming to PureScript? Something analogous to Template Haskell maybe?

I think it could be a really important feature especially now that there’s talk of stabilizing the language. It would give users more freedom to do things on their own. For example the recent magic typeclasses could have been implemented without compiler support.

Taking Template Haskell as inspiration are there any things we would like to do differently? There are some interesting points here, specifically I think phase distinction could be valuable.

Then there’s the obvious question of how compile time code is evaluated. Personally I think it’s fair to just model it after repl. If you are using the purescript/purescript compiler you would need a JavaScript interpreter for compile time code. Backends that are forks will just call out to their own thing if possible (or also require a JavaScript interpreter) and libraries with compile time code will have to have implemented the FFI for that backend, same situation as today with run-time code.

5 Likes

The primary thing I find annoying about Template Haskell is that it vastly increases compile time.
Having experienced this in a yesod application where maybe it’s used more than it needs to be which, could be the source tbh.

Unfortunately that’s all I can offer as my Template Haskell knowledge is fairly limited :smiley:

1 Like

To quote @paf31, “I can count on no hands how many times I’ve wanted template PS”

3 Likes

Hehe, I had a feeling there wasn’t much interest in this ^_^

Citation needed :stuck_out_tongue:

1 Like

Perhaps I worded that badly :slight_smile: I meant that many functions that use typeclasses purely for computing types can use compile time metaprogramming instead. But also if we had something like TH we could maybe allow users to solve functional dependencies like class Wat a b | a -> b themselves with a function of the type
Q Type -> Q Type.

But I guess Template Haskell is another story :relaxed:

I think the crux of it is that Template Anything is extremely non-trivial for both implementation and maintenance, especially one that’s done well. It would probably require:

  • A comprehensive proposal for how such a system would work and fit into the existing compiler (parsing, type-checking, staging, hygiene, etc).
  • An implementation in a fork for everyone to use and evaluate.
  • A commitment to maintain it long term.
  • Approval from the core developers as to whether this is something we should include.
3 Likes

Yeah it being extremely non-trivial is precisely the point of this post, before one invests the time, would something very similar to Template Haskell possibly get past bullet point 4?

1 Like

I’m not a core developer, but I would say those things have to happen in order. How would one be able to evaluate whether it’s good for the tooling and community if there is no concrete proposal for how it would affect the tooling and community? PureScript isn’t Haskell, and it has different constraints. If you want an answer to, “Can I get a binary yes/no for inclusion of Template Haskell in the PureScript compiler?”, then I think it’s pretty clear what the response would be :smiley:. My impression is that I haven’t seen a core developer express interest in building or maintaining such a feature (I could be wrong though), so it would require someone with a lot of commitment/vision/experience to see it through, and fight a fairly uphill battle.

Another avenue might be whether or not this can be addressed by extended tooling, rather than an internal compiler feature. Would it be possible to setup some tool to perform the necessary staging and coordination of the compiler?

If the view expressed in the quote from Phil (that this simply isn’t useful or wanted) is widely held, then going over a detailed proposal seems futile. The motivation for Template Haskell is widely documented, even more so for compile time metaprogramming in general. PureScript having different constraints seems to me a matter of implementation, not motivation.

Extended tooling as in something the compiler would call out to or something completely separate?

3 Likes

Hope it’s alright to float this discussion into meta-programming in PureScript in general.

There are forms of meta-programming which are different from Template Haskell, such as typed, hygenic macros as popularized in Scheme and demonstrated in an ML language (the family to which PureScript belongs) in the cyrus-/relit for Reason (a kind of Ocaml) project and paper.

I imagine one thing that puts people off of Haskell is Template Haskell. I don’t understand the inner-workings of Template Haskell and I was never able to find a resources for learning it, so I have grown a distaste for it. So, I’d prefer a different means of meta-programming in PureScript (a Haskell-like language). Because it’s included in GHC I guess GHC maintainers would likely not want to merge another meta-programming tool.

This argument leads us to a meta-programming system separate from and external to the compiler itself. (Perhaps this compiler-external meta-programming idea is what @natefaubion was referring to?) I would guess this would involve updating the PureScript compiler to allow registering an external meta-programming tool with the compiler, perhaps one meta-programming tool per module.

1 Like

Sounds like a scripting language/build system would be enough to coordinate external tools.

So, a build system would pre-process a PS program using an external tool? I think this means whatever language the meta-programming system is written in would need to have a full PS-lang parser or pretty-printer. It’s interface would be something like PureScriptString -> PureScriptString. That sounds a bit like a hurdle, but a reasonable ask.

At first glance, then, it seems the big advantage of having a hook in the compiler for this, like a suggested a post above, would be to make an external meta-programming tool easier to write, as the compiler could pass the parsed PS AST directly to the tool for transformation, like PSAST -> PSAST. (this sounds like Template Haskell :sweat:)

This latter concept presumes the embedded language is a successfully parsed PureScript expression, while the former would allow embedding an expression in any custom language into a PureScript program. If we want to avoid prescribing Template Haskell, then the former (like I would prefer) sounds like an obvious way to go.

I’m probably missing a big point here, though, as I’m not familiar with many meta-programming facilities of languages.

Parsing functional core is significantly simpler.

1 Like

After copy/pasting about 20 line blocks of deriving Generic multiple times for BoundedEnum, then changing one string occurrence per copied block, I am tempted to try m4 or something similar. Are there any opinions on good options in this area?

3 Likes

It would be cool to look at an approach similar to what Java does. Code generation is omnipresent in the Java community, but it’s not built into the language. Instead, you can put custom annotations on various syntactic constructs, and a standard tool is provided to parse annotations. Writing an annotation processor is orders of magnitude easier than writing your own parser.

I suppose you could even build this in Purescript without changing the language at all by writing a standard annotation processor that stripped annotations before passing them to purs.

1 Like

@thurn, as to the first suggestion, it looks like GPP might be a way to accomplish this. It isn’t in PureScript, though, of course.