What is the best way to start a GHC proposal

Thanks you all for the links.

I’m not pushing for untyped string vs Q, just to have a lighter macro system.
By lighter I mean

  • a) no sectioning of the file (order shouldn’t matter) when possible
  • b) being able to use functions definition in the same file
  • c) not having to learn a new “language”: use quotation as much as possible
  • d) avoid unnecessary recompilation
  • e) resiliant to GHC internal changes

I realized that TH is more capable than I though it was (thanks to @rhendric) and there already some discussions going own about how to improve the situation (even though it seems a bit all over the place).
To summarize

The use of let clauses addresses b) in some cases (maybe it could be added explicitely in the wki) but doesn’t allow “in place” definition of quasiquoter (correct me if Y am wrong).

Provide basic QuasiQuoters in template-haskell might helps.

#529 Untyped Template Haskell quotes as patterns seems promising and could help with c) and e).

Introducing a difference between pure and impure splices (as @michealpj suggested ) could help with d) (if there is really a problem there): A pure splices should only depends on the input files and as such needs only need to follow “normal” file recompilation rules.

This leave a) (which I believe is called “stage restriction” unless it is the name for b) or both). I am still not sure if this problem
is only the result of implementations detail or if there is something deeper to it and if there is a difference between splies $(..) and quasi quoting ([|...|])
But my intuition is that things like using quasi quoting to do string interpolation or precalculating constants should be able to work without affecting the order in which things are defined.

Finally, there seems to be two discussions regarding stability ( point e)) one on gitub and one on gitlab
Which one is the most relevant ? Do we need something to coordinate (tidy?) all those effort ?

You proved me quotations were more convenient that I remembered so I gave it a look again.

It doesn’t seem that you can use $... in data declaration, to do things like

let a = "A" in [d| data $a = $a |]
-- or
let i = "Int" in [d| data A = A $int |]

Am I missing somethnig or is it not possible ?
If not that is a new argument in favor of string based macro.

I think the first does require the TH API; splices have to be expressions, patterns, types, or entire declarations, and what you want to splice there is none of those things (maybe this list could be expanded).

The second can be done with just quotes:

let
  i = [t|Int|]
  in [d|
    data A = A $i
  |]
1 Like

In defense of staging: any macro system, be it Template Haskell or some new thing you come up with, is going to have to contend with the dueling desires that some people will want to use (not just mention, but invoke or construct) in their macro code a function or type defined normally in the same module, and other people will want to use in normal code a function or type defined in a macro in the same module. Staging makes both patterns possible—you can define types and then macros that use those types and then functions that use those macros and then more macros that use those functions and so on.

Without staging, I don’t think there’s a way to achieve this. Your proposed solution of running all the macros first and then compiling the normal code certainly doesn’t—if running the macros requires running the normal code, you can’t wait until after the macros run to compile the normal code.

But with staging, you can choose to implement the pattern of macros-first-then-normal-code simply by, well, putting all your macros before your normal code. If you are only mentioning, and not using, names from the normal code in your macros, there is no issue with staging per se, other than the purely aesthetic complaint of perhaps not wanting all of your macros to come first. That seems like a very small price to pay for the flexibility that staging gives other people with other macro-use-pattern desires. It also seems like a very small price to pay to keep everyone on one macro system where we can pool our bug-fixing, documenting, and educating efforts, instead of having two even-more-poorly documented etc. implementations of macros for Haskell users to choose between.

Edit: GHC is probably more restrictive about staging than it needs to be; I’m not arguing that the status quo is ideal. I’m just arguing that aiming for ‘order doesn’t matter’ goes too far.

So how does Clean’s macro system work? Perhaps an explanation of how it works may prove useful to others here.

Re Clean, I suppose I should have said ‘any macro system supporting arbitrary compile-time computation’ instead of ‘any macro system’.

…anyone for Safe Template Haskell ?

So I don’t know Clean, and the website isn’t very detailed. But from the online guide, it looks like Clean doesn’t support calling external functions in a macro. The only example there shows calling a function defined in a where block.

Thanks for that (I had wondered if anyone knew about the 3.1 release’s macro system). So Clean 2.2’s macro system ensures that:

The compile-time substitution process is guaranteed to terminate.

Is there a similar mechanism for TH? Or does “arbitrary” include ?

Oh ho ho, not only does it include divergence, it includes anything you can do with IO and, as has already been linked in this thread, breaking out into the compiler internals.

It’s a good thing play.haskell.org does both its compilation and its execution in a sandbox.

…yeah, thanks - I was thinking more about Turing-completeness than that other “ugly stuff” (which I had already seen). But having all that together in one convenient “bite-sized” answer will also be useful…as a warning to future implementors.

… Huh. If I/O were possible but internal-to-the-language divergence wasn’t, would that actually matter to you?

I may have an answer to that…but it’s probably too far off-this-topic; a new thread seems more appropriate for it.

That is missing the point. I would like to be able to use "Int" as a value which comes from somewhere (like a file or the result of a function) , not a hard coded value.
So yes quotation are very convenient but they are (in there actual form) very limited. It seems that everything related to types (type name, constructor etc …) can not be anti-quoted which is really inconvenient if your creating for examples new types from others.

It could be the result of a function:

foo True = [t|Bool]
foo False = [t|Int]

...

  [d| data A = A $(foo (even 7)) |]

Getting it out of a file is more difficult. It’s still possible if the file is only choosing from a fixed set of types (possibly inifinite), but it cannot just name any string as a name. Although you can do that with ConT (mkName "Int"), which is probably a pretty stable and lightweight part of the API. But that is also highly unsafe as the name might not exist.

1 Like

I understand that there is a need for staging things and I might have no use the correct word.
What I mean is what is referred as declaration groups

I don’t want to and I am happy to separate (within the same file) the code to run as macro and the code to be compiled (maybe a bit like how literate haskell work). TH mixes both codes, for example you use the same import section to import code to be compiled (and which need to be linked) and code that you only need to generate the code (which needs to be linked at compile time but not at run time). Maybe what I am describing is more a pre-processor than a macrosystem. I agree that this “system” might be able to do everything that TH does , but it could some it in a simpler way or some other than TH can’t do (like using String in data splices).
We could have both system.

Anyway, are you trying to help me to design such a system (which might result in extending in TH) or just to prove me that I should just give up.

Why does everybody take everything literally in this forum ?

Ok, you used a function but the final types are still hard coded ([t|Bool|] and [t|Int|]) which defeats the point of metaprogramming.

When I said function I means things like (++ "F") So I can create FooF from Foo.

Yes, but @rhendric was talking about quotation and was trying to find example where quotation were not sufficient.

It was an example, and I actually I have had problems with ConP which isn’t stable.

But I got the message, everybody is there to defend Template Haskell and I am fighting a lost battle so I shant’ bother.

I am trying to dissuade you from proposing sweeping reforms without adequately understanding the existing solution. I am not trying to convince you to give up on improving the status quo. But whatever forms your efforts take, I expect you’ll be more successful if you put more energy into looking for the good in what exists instead of starting from scratch and trying to make what exists conform to your vision of the ideal. You’re not the only person to have thought about what ideal Haskell metaprogramming would look like!

I’m also trying to dissuade you from this. Template Haskell is already poorly understood by many; how much worse would it be if there were two macro systems for users to choose from?

2 Likes

So TH is so bad

that it needs to be protected from an eventual competition … bizare

That’s a pretty massive reinterpretation of what I said, but okay. Good luck with your proposal.