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

Oscar Finnsson oscar.finnsson at gmail.com
Thu Oct 29 17:26:41 EDT 2009


Thanks for the pointers. Using the GHC API I've managed to extract the
names and types of exported functions from other packages (haven't
managed to figure out how to extract from the modules in the current
package but I'm working on it). I'll post the source code of my
"reifyModule" on github once it is cleaned up.

First I thought I would examine the source code of template-haskell
(more specifically qLocation and qReify) to figure out how to do it
but got stuck. Obviously I have still much to learn when it comes to
Haskell.

Could someone explain how Quasi works?

I see:

instance Quasi Q where
  qReify    = reify
  qLocation = location
  ...

instance Quasi IO where
  qLocation = badIO "currentLocation"
  qReity = badIO "reify"
  ...

location :: Q Loc
location = Q qLocation

I guess this means that a Q will ask the embedded Quasi for the
location until the Quasi either returns badIO "currentLocation" or
...?
The only way this can work (as fast as I can see) is if where is
another instance of Quasi than Q and IO but I cannot find that
instance in the source code.

-- Oscar


On Tue, Oct 20, 2009 at 4:38 PM, Simon Peyton-Jones
<simonpj at microsoft.com> wrote:
> [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 at haskell.org [mailto:template-haskell-
> | bounces at haskell.org] On Behalf Of Oscar Finnsson
> | Sent: 16 October 2009 18:47
> | To: template-haskell at 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 at haskell.org
> | http://www.haskell.org/mailman/listinfo/template-haskell
>
>


More information about the template-haskell mailing list