RE: [Template-haskell] How to extract name and type of exported functions in modules

[ccing ghc-users] | I'm trying to extract the names and types of exported functions in a module. Quite a reasonable request. But it's not conveniently possible at the moment. Here's what you can do in the Q monad: class (Monad m, Functor m) => Quasi m where -- Fresh names qNewName :: String -> m Name -- Error reporting and recovery qReport :: Bool -> String -> m () -- Report an error (True) or warning (False) -- ...but carry on; use 'fail' to stop qRecover :: m a -> m a -> m a -- Recover from the monadic 'fail' -- The first arg is the error handler -- Inspect the type-checker's environment qReify :: Name -> m Info qLocation :: m Loc -- Input/output (dangerous) qRunIO :: IO a -> m a But you want one more function: qReifyModule :: String -> m ModuleInfo where ModuleInfo is something like: data ModuleInfo = MI { mi_exports :: [Name] , ... instances,rules, etc } Then you could use qReify to get info about a particular thing. This would not be hard in principle, the details need thought. For example, if module exports T( C1, C2), where C1, C2 are constructors of T which also has constructors C3, C4, what should appear in mi_exports? Should mi_exports reflect the structure of the export list (see the AvailInfo type in GHC). What is the info for an instance? Do we need a way to ask for all the instances of a class (or rules for a function) regardless of what module those instances come from? etc Does this ring bells for anyone else? Would someone like to write the spec? Are there other reify-related things that we need? Simon | -----Original Message----- | From: template-haskell-bounces@haskell.org [mailto:template-haskell- | bounces@haskell.org] On Behalf Of Oscar Finnsson | Sent: 16 October 2009 18:47 | To: template-haskell@haskell.org | Subject: [Template-haskell] How to extract name and type of exported functions in | modules | | Hi, | | I'm trying to extract the names and types of exported functions in a module. | | At the moment I've managed to get a list of all functions in a module | but I can't seem to figure out how to get their types. | | Lets say I got the module | | module Foo where | | foo1 :: String -> String | foo1 value = value | | foo2 = "hej" | | and then in anothor module... | | module Bar where | | bar = $(getAllFunctions "<some-path>/Foo.hs") | | At the moment I got getAllFunctions returning ["foo1","foo2"], but I | would really like to get it to return [("foo1",AppT (ConT "String") | (ConT "String")), ("foo2",ConT "String")] | | Using "parseModuleWithMode" from Language.Haskell.Exts I can get hold | of the names and the type signature of foo1 (since it's specified in | the source code) but I cannot get hold of the type signature of foo2 | (since it's not specified in the source code). | | Is there another way to get the names/signatures of exported functions | from a module other than using parseModuleWithMode so the developer | writing the Foo-module isn't forced to explicitly supply type | signatures of the exported functions? | | If I try "reify" to get information about the functions I get the error message: | "foo1 is not in scope at a reify" | | This seems to be a known bug about reify (reported here | http://hackage.haskell.org/trac/ghc/ticket/2339). My problem is that I | cannot use the workaround since I don't know the name of the | functions. | | Another disadvantage with this approach is that "getAllFunctions" must | have access to the source code of the module and that I must supply | the path the the module. If possible I would like to have code such as | | bar = $(getAllFunctions "Foo") | | instead of "<come-path>/Foo.hs". | | Regards, | Oscar Finnsson | _______________________________________________ | template-haskell mailing list | template-haskell@haskell.org | http://www.haskell.org/mailman/listinfo/template-haskell

Simon Peyton Jones wrote:
What is the info for an instance? Do we need a way to ask for all the instances of a class (or rules for a function) regardless of what module those instances come from? etc
Does this ring bells for anyone else?
It does --- but completely outside the context of Template-Haskell. I have been trying to do things via the GHC API (the full API, not just module GHC), and found it surprisingly hard to obtain all exports for a given module (whether source or compiled library module): -- If it exports any prelude indentifiers (not only the Prelude itself, but also for example Data.List), I have no idea how to get at their types --- lookupGlobalName does not find them. -- I cannot find any re-exported instances. The ``package InstEnv'' obtained from tcGetInstEnvs after loading a library module interface (via findAndReadIface) seems to contain only the module's own exported instances, which are the same instances I also find via mi_insts. (For source modules, where I use typeCheckModule, I've only been able to find the module's own exported instances via hptInstances). Even while not counting the missing Prelude instances, Data.Map is still re-exporting the Data.Set instances from the same package --- where does GHC keep those? And where does it keep those from different packages? my current understanding of the ``home InstEnv'' is that it contains instances encountered during ``ghc --make'' that may not be visible in the current module, so if I ever do find instances there, how would I filter the visible ones?
Do we need a way to ask for all the instances of a class (or rules for a function) regardless of what module those instances come from? etc
As long as a module re-exports an instance, I'd like to be able to find it from that module.
For example, if module exports T( C1, C2), where C1, C2 are constructors of T which also has constructors C3, C4, what should appear in mi_exports? Should mi_exports reflect the structure of the export list (see the AvailInfo type in GHC).
Applications that look at a module ``from the outside'' should, in my opinion, not be able see C3 and C4. I think they also do not need to be able to know that there are additional constructors. There is always _|_ that doesn't match C1 nor C2, even if there are no C3 nor C4. Applications that need to know more will want an interface that allows to ``look at all the insides'' of a module, i.e., they want access to all items defined and imported inside, and may of course also want to know which of these items are exported. Since there are other interfaces to find out that C1 and C2 belong to T, I don't think it is essential to know the structure of the export list. It may be convenient, though... (By the way, IIRC, sometimes I can import C1 as ``C1'', and sometimes I need to import it as ``T(C1)''. Is this a side effect of some LANGUAGE extension?) Wolfram

| -- If it exports any prelude indentifiers (not only the Prelude itself, | but also for example Data.List), I have no idea how to get at | their types --- lookupGlobalName does not find them. Well, it claims that it should find them. Would you like to make a reproducible test case and file a Trac bug report? | -- I cannot find any re-exported instances. The ``package InstEnv'' | obtained from tcGetInstEnvs after loading a library module interface | (via findAndReadIface) seems to contain only the module's own exported | instances, which are the same instances I also find via mi_insts. | (For source modules, where I use typeCheckModule, | I've only been able to find the module's own exported instances via | hptInstances). Hmm. GHC does not read every interface file for every module in every package that is transitively visible from the current module. Instead it relies on the fact that before an instance (C T) is useful, you must have a hold of Class C and TyCon T. So you'll have loaded *their* interfaces, and thereby loaded their instances. (Except for orphan instances, which *are* loaded eagerly.) I can see that this is inconvenient; on the other hand, do you really want ALL the instances of Ord, say? Perhaps there should be an interface for load instances that relate to the following Names Indeed, there is: LoadIface.loadInterfaceForName. Does that help? What's the desired behaviour? I really wish there was someone who took ownership for the GHC API, as seen by "customers" of the API. At the moment it grows incrementally, without proper design. Maybe no one feels able to, because they think GHC HQ will do it, but (a) we are too busy and (b) we represent the suppliers of the API, not the customers. Any volunteeers? Simon
participants (2)
-
kahl@cas.mcmaster.ca
-
Simon Peyton-Jones