Opened 5 years ago

Last modified 4 years ago

#9699 new feature request

TH function to list names in scope

Reported by: MikeIzbicki Owned by:
Priority: normal Milestone:
Component: Template Haskell Version: 7.8.3
Keywords: Cc: spinda, mgsloan
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: None/Unknown Test Case:
Blocked By: Blocking:
Related Tickets: Differential Rev(s):
Wiki Page:

Description

I [asked about this on stackoverflow](http://stackoverflow.com/questions/26394199/using-templatehaskell-to-list-all-names-in-a-namespace), and apparently it doesn't exist yet.

I want a TemplateHaskell function variablesInScope :: Q [Name] that returns a list of the Name's of all the variables in scope. TemplateHaskell obviously has this information available in order to implement functions like reify :: Name -> Q Info and lookupValueName :: String -> Q (Maybe Name). So it seems like this might be a pretty simple function to add.

Change History (6)

comment:1 Changed 5 years ago by simonpj

Indeed it would not be hard. I'd be open to patches.

There are open design questions. Do you mean "all names in scope" (including imported ones)? There may be a lot of those. Or just those bound in this module? Or just those bound by nested (non-top-level) definitions?

Moreover, although, say Data.List.partition may not be lexically in scope, it's fine to generate a TH program that refers to it, thus:

module Foo where
import Bar( bar )
f x = $(bar 5)

where bar is a TH function in another module Bar where Data.List.partition is in scope, and (bar 5) expands to code mentioning partition. So, is Data.List.partition "in scope"?

As ever, getting the specification right (and precise) is a big part of the work!

Simon

comment:2 Changed 4 years ago by spinda

Attempt at a rough specification:

(1) Extend ModuleInfo (obtained from reifyModule) to ModuleInfo [Module] [Name], where [Module] is still the import list and [Name] contains the module's list of exported names.

(2) Add thisModule :: Q Module producing the current Module.

(3) Add topLevelNames :: Q [Name] producing a list of top-level names (both exported and non-exported) bound in the current module that would be visible to reify.

(4) Add nestedNames :: Q [Name] (in need of a better name) producing a list of the non-top-level (nested) names visible to reify in this context.

(5) Add parentNames :: Q [Name] (also in need of a better name) producing a list of the names immediately associated with the current splicing context, if available. For example, foo, bar :: $(typeSplice) would see [foo, bar], foo = $(exprSplice) would see [foo], and $(topLevelDecSplice) would see [].

(6) Optional Add isTopLevel :: Name -> Q Bool to detect whether a name is bound at the top level (of the current module?). Something like this could alternately be accomplished by searching through topLevelNames.

Last edited 4 years ago by spinda (previous) (diff)

comment:3 Changed 4 years ago by spinda

Cc: spinda added

comment:4 Changed 4 years ago by MikeIzbicki

This interface would work for my use case.

Last edited 4 years ago by MikeIzbicki (previous) (diff)

comment:5 in reply to:  2 Changed 4 years ago by goldfire

Replying to spinda:

Attempt at a rough specification:

Thanks for putting this together. It's usually best to put this sort of specification on a (fresh) wiki page, so it can evolve more easily that is possible in a comment chain.

A few reactions to the spec:

  • The current module's list of exported names might include names that are not in scope, due to top-level splices. Recall that in a top-level splice, definitions below the splice are not yet in scope, yet might be mentioned in an export list. And there might be exported names that there is no way to know about: for example, if the export list says T(..) and T's definition is below a top-level splice, I doubt strongly GHC knows what constructors are in T when processing the top-level splice.
  • Rename nestedNames to localNames?
  • parentNames is underspecified. (What is returned within a type splice within an expression? What about a let-bound expression? What about in patterns?) I further believe that any tight specification will be woefully long and intricate. What is the expected use case of such a function?

comment:6 Changed 4 years ago by mgsloan

Cc: mgsloan added
Note: See TracTickets for help on using tickets.