noughtmare / ghc-meta

Parse Haskell code to Template Haskell types using GHC's own parser.
GNU General Public License v3.0
2 stars 0 forks source link

Two remarks #1

Open amesgen opened 3 years ago

amesgen commented 3 years ago

Very cool project! Two remarks:

If I have time, I will try to create PRs to work on these things.

noughtmare commented 3 years ago

Thanks for the suggestions. I hope that ghc-lib-parser will eventually get separated better so that it is smaller and faster to compile, but now we indeed do not really notice those benefits yet (and ghc is always already built). So, for now, it is a good idea to switch back to the ghc library.

I don't know if ghc-api-compat will really be useful. Its use-case seems to be the opposite of what I want. I want to use the newest API and then have compatibility with older APIs, but that package seems to expose an old API and compatibility with newer APIs. I have no idea how that would work with newly introduced language features such as linear arrows which you already mention and it means we wouldn't be able to benefit from improvements to the API in newer versions.

About fixity, currently I'm using UInfixE, which I think should automatically adapt to the fixity of the operators that are in scope in the place you splice the TH into. The reifyFixity function would get the fixity from the scope in which the expression is built, that might not actually always be what we want, but it might be nice to have a choice.

Contributions are very welcome!

amesgen commented 3 years ago

I don't know if ghc-api-compat will really be useful. Its use-case seems to be the opposite of what I want. I want to use the newest API and then have compatibility with older APIs, but that package seems to expose an old API and compatibility with newer APIs. I have no idea how that would work with newly introduced language features such as linear arrows which you already mention and it means we wouldn't be able to benefit from improvements to the API in newer versions.

ghc-api-compat only provides a unified module layout for different ghc versions; it does not change the types/functions/etc. But I agree that it would be nicer if it tried to backport the latest module hierarchy to older versions, not the other way around like it is right now.

About fixity, currently I'm using UInfixE, which I think should automatically adapt to the fixity of the operators that are in scope in the place you splice the TH into. The reifyFixity function would get the fixity from the scope in which the expression is built, that might not actually always be what we want, but it might be nice to have a choice.

It is necessary to reassociate the parse tree to account for the fixities of the operators, as operators are initially all parsed using the default fixity. An example: id $ 1 + 1 is parsed as

UInfixE (UInfixE (VarE id) (VarE $) (LitE (IntegerL 1))) (VarE +) (LitE (IntegerL 1))

which is equivalent to (id $ 1) + 1, as all operators are by default left associative with the same precedence.

Also, the reifyFixity function operates in the Q monad, so it is "executed" when it is spliced at the usage site (where the reassociation has to happen).

noughtmare commented 3 years ago

which is equivalent to (id $ 1) + 1, as all operators are by default left associative with the same precedence.

I believe the UInfixE constructor means that the fixity will be resolved at the splice-site, it is not like the InfixE constructor which forces fixity. But I can't find the relevant documentation. The template-haskell package sorely lacks documentation.

See this example:

ghci> $(uInfixE [|2|] [|(*)|] (uInfixE [|1|] [|(-)|] [|1|]))
1
ghci> $(infixE (Just [|2|]) [|(*)|] (Just (infixE (Just [|1|]) [|(-)|] (Just [|1|]))))
0
amesgen commented 3 years ago

Ah very cool, that makes it way easier! I should have tested actually splicing the expression.