Open amesgen opened 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!
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. ThereifyFixity
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).
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
Ah very cool, that makes it way easier! I should have tested actually splicing the expression.
Very cool project! Two remarks:
ghc-lib-parser
, I think that for this project it is a better idea to use the parser via theghc
package as it is not possible/useful to parse e.g.LinearArrows
constructs while running GHC 8.10, as it can't be converted to TH.ghc-api-compat
could be used to remove some CPP.reifyFixity
), using machinery similar toLanguage.Haskell.GhclibParserEx.Fixity
.If I have time, I will try to create PRs to work on these things.