Does template haskell move things out of the scope?

Ok, I don’t know how to express this problem. But I have some (micro-)lenses created with template haskell. Depending on the position of the makeLens function call, the code compiles or not. The weird thing is that failure happens because a type synonym is out of scope, but if I move further the makeLens call, then It is in scope again.

I just recorded a gif because is too rare to explain.

type_error

I would understand that if suffixLenses create from sort of type and you depend on that type well… something could be wrong with respect code order… but St does not depend on suffixLenses

1 Like

This is one the main issues with TH : it chops your file in sections and only what is above a splice is in scope.

3 Likes

You have been bitten by splicing scope. Template Haskell declarations are grouped, then dependency analysis etc. is performed in the first group, then going to second group (where group one is now in scope) etc.

It is indeed very frustrating when you are used to plain old Haskell, i.e. moving declarations where they make sense instead of juggling with intra-file scope.

Disregarding its undeniable usefulness, Template Haskell will always feel like an afterthought when comparing it to other metalinguistic tools like Scheme/Lisp macros.

9 Likes

It’s a shame that we are happy with TH as it is and there is no attempt to find a way to some design a templating solution which works.

I’m having trouble imagining how a version of Template Haskell that retains all of the capabilities it currently has would be able to lose this restriction, honestly. Even Scheme macros can only use the environment that exists when they’re expanded.

2 Likes

With the way it has been designed you are probably right, that doesn’t mean that there are no other ways which might be more practical (but which might have their own drawbacks).
One can imagine a system where the file parses everything it can (skipping slices) and then reparse the slice accordingly or something.
Another approach would be to have a proper macro system which just expand code blindly (or as text) which is then parsed as Haskell.
I am sure there plenty of other possibilities.

I mean, if you want CPP, you can use CPP.

I’m very glad we have typed and type-aware macros, though.

CPP is only half supported. It is an external dependencies and it breaks Haskell multiline syntax.

What would like is typed as type-aware macro (which we don’t have).
A typed type aware version of CPP would not have the splice scope/restriction.
The problem is TH doesn’t have two stage (as a macro would have, first step expand the macro, second step parse it). Instead it mixes the parsing of the file and the expansion (to bring into scope the AST of what has been previously declared).
This is indeed nice (when you need it) but has he major drawback that it introduces “splicing scope”.
There are many instance when this no needed (i.e. when using TH as a macro) and it would be nice to not have the splicing scope issue when it is not necessary.

This is my problem. Everybody seems to think TH is fine, yet people avoid it if possible. There must me something in between CPP and TH.

I think pretty much nobody is happy with TH “as it is”/nobody thinks it’s “fine”. It’s just that it took a huge amount of work to get it to the state it’s in/nobody can think of ways to improve it much without in effect scrapping it and starting again/an even huger amount of work. (There have been occasional mutterings about something completely different. The most annoying behaviour is that you have to compile the module containing your TH definition(s) before you can compile the module using them.)

It’s usually adequate for Lenses.

Are there other generic macro tools (more powerful than CPP) that would do better specifically with Haskell? (I think they wouldn’t be "between CPP and TH". Rather they’d branch out in a different direction from CPP, not on a path to TH.)

For the record, here’s a StackOverflow q for the same issue.

The answer’s link to the User Guide has bitrotted. I think it means here.

Yeah there used to be a CPP-alike written in Haskell, but which played better with multiline syntax.

You could still use it, I guess, but it fell out of use because typically you’re building a project with components in all sorts of source languages, cpphs doesn’t play so well with non-Haskell source.

CPP does require your #defines to appear before usages of the macro, so you still don’t get Haskell’s usual free ordering.

At the very least it seems like the error message here could be better.

1 Like

The message was better before 9.x. I filed an issue on error-messages.

5 Likes