Using the GHC API: pretty printing with qualified names

Hello, I'm the maintainer for EclipseFP, which involves using the scion library and the GHC API to provide IDE functionality. I have a little issue that no doubt stems from me not understanding the GHC API well, and I would be grateful for any light on the matter. I'm trying to give the user the possibility to jump to the definition of a symbol in the source file. You click on the name of a function and you're send to the module where it's defined. So I have an AST, and somewhere down the line I have an Id object representing that function call. Then I just use ppr alwaysQualify id to get the fully qualified name of the function, and I can then use the module name to retrieve the source file etc. This works well in cases, but not in others. It will sound silly to the gurus on the list, but it's when the function has generics that it doesn't work. So a function with a type class in its type signature will never be printed qualified. It kinda like makes sense because I suppose some work has been done so that it represents the function with proper types, etc., but how can I get back to the original Id? How can I get back from that unqualified Id to the qualified Id representing the function in the original module? I've been looking round Name and OccName and all that but I'm not sure really what I'm looking for. Hope I'm making sense!! Thanks! -- JP Moresmau http://jpmoresmau.blogspot.com/

On 17 November 2010 19:21, JP Moresmau
Hello, I'm the maintainer for EclipseFP, which involves using the scion library and the GHC API to provide IDE functionality. I have a little issue that no doubt stems from me not understanding the GHC API well, and I would be grateful for any light on the matter. I'm trying to give the user the possibility to jump to the definition of a symbol in the source file. You click on the name of a function and you're send to the module where it's defined. So I have an AST, and somewhere down the line I have an Id object representing that function call. Then I just use ppr alwaysQualify id to get the fully qualified name of the function, and I can then use the module name to retrieve the source file etc. This works well in cases, but not in others. It will sound silly to the gurus on the list, but it's when the function has generics that it doesn't work. So a function with a type class in its type signature will never be printed qualified. It kinda like makes sense because I suppose some work has been done so that it represents the function with proper types, etc., but how can I get back to the original Id? How can I get back from that unqualified Id to the qualified Id representing the function in the original module? I've been looking round Name and OccName and all that but I'm not sure really what I'm looking for. Hope I'm making sense!! Thanks!
Note that typeclass methods all live in a top-level namespace. Qualified names are used to disambiguate between multiple names which this is not necessary for method names. I presume when you want to jump to the definition of a method, you want to do something special anyway. You probably want to jump to the implementation of the method for the type at which it is used. If it is used polymorphically you cannot do this (there is no statically known definition), so you could just display its type or a list of all known implementations. To find out the type at which a polymorphic or overloaded identifier is used, you have to interpret type applications (HsWrap) and abstractions (AbsBind). The GHC API provides access to all imported instances, but they probably won't have source code annotations. Such a database must be created separately. HTH / Thomas -- Push the envelope. Watch it bend.

On Wed, Nov 17, 2010 at 9:21 PM, Thomas Schilling
On 17 November 2010 19:21, JP Moresmau
wrote: Hello, I'm the maintainer for EclipseFP, which involves using the scion library and the GHC API to provide IDE functionality. I have a little issue that no doubt stems from me not understanding the GHC API well, and I would be grateful for any light on the matter. I'm trying to give the user the possibility to jump to the definition of a symbol in the source file. You click on the name of a function and you're send to the module where it's defined. So I have an AST, and somewhere down the line I have an Id object representing that function call. Then I just use ppr alwaysQualify id to get the fully qualified name of the function, and I can then use the module name to retrieve the source file etc. This works well in cases, but not in others. It will sound silly to the gurus on the list, but it's when the function has generics that it doesn't work. So a function with a type class in its type signature will never be printed qualified. It kinda like makes sense because I suppose some work has been done so that it represents the function with proper types, etc., but how can I get back to the original Id? How can I get back from that unqualified Id to the qualified Id representing the function in the original module? I've been looking round Name and OccName and all that but I'm not sure really what I'm looking for. Hope I'm making sense!! Thanks!
Note that typeclass methods all live in a top-level namespace. Qualified names are used to disambiguate between multiple names which this is not necessary for method names.
I presume when you want to jump to the definition of a method, you want to do something special anyway. You probably want to jump to the implementation of the method for the type at which it is used. If it is used polymorphically you cannot do this (there is no statically known definition), so you could just display its type or a list of all known implementations.
To find out the type at which a polymorphic or overloaded identifier is used, you have to interpret type applications (HsWrap) and abstractions (AbsBind).
The GHC API provides access to all imported instances, but they probably won't have source code annotations. Such a database must be created separately.
HTH
/ Thomas
-- Push the envelope. Watch it bend.
Thanks very much, but I'm not sure it that's the situation here. I don't mean methods on typeclasses but function defined as operating on typeclasses. For example: I have this function: overlaps :: SrcSpan -> SrcSpan -> Bool which when pretty printed gives me a qualified name And this one: findHsThing :: Search id a => (SrcSpan -> Bool) -> a -> SearchResults id Which doesn't. So findHsThing work on any Search id a, but there is only one implementation of that in one source file. So there should be a link between what's in the AST that may be using more specific type and the implementation. Thanks, -- JP Moresmau http://jpmoresmau.blogspot.com/

I'm trying to give the user the possibility to jump to the definition of a symbol in the source file. You click on the name of a function and you're send to the module where it's defined. So I have an AST, and somewhere down the line I have an Id object representing that function call. Then I just use ppr alwaysQualify id to get the fully qualified name of the function, and I can then use the module name to retrieve the source file etc. No, no, don't do this. The ppr alwaysQualify thing tries hard to display the thing *in the current scope*. So if you have import M as N it will, I think, print thing as N.f, N.g, etc, not as M.f, M.g. The intent is to give user-comprehensible error messages. What you want is to use idName :: Id -> Name nameModule_maybe :: Name -> Maybe Modlue The latter gives you the *defining* module for the Id, which is what you wanted. It returns nothing for local variables (e.g. lambda-bound). This works well in cases, but not in others. It will sound silly to the gurus on the list, but it's when the function has generics that it doesn't work. So a function with a type class in its type signature will never be printed qualified. It kinda like makes sense because I suppose some work has been done so that it represents the function with proper types, etc., but how can I get back to the original Id? How can I get back from that unqualified Id to the qualified Id representing the function in the original module? I've been looking round Name and OccName and all that but I'm not sure really what I'm looking for. Suppose we have List.sort :: Ord a => [a] -> [a]. And the program is f x = sort [x,x] Then, after type checking, the code looks more like this: f :: Ord a => a -> [a] f = /\a. \d:Ord a. let s :: [a] -> [a] s = List.sort a d in \(x:a). s [x,x] Notice the local function 's'. (Well, its string-name is still "sort", but it's not the global List.sort.) I think you are poking on 's'. Happily, GHC 7 takes a simpler approach, and instead generate something more like f :: Ord a => a -> [a] f = /\a. \d:Ord a. \(x:a). List.sort a d [x,x] So it may "just work" in GHC 7. Hope this helps. Good luck with EclipseFP. We need a good Haskell IDE. Simon

Hello, I'm the maintainer for EclipseFP, which involves using the scion library and the GHC API to provide IDE functionality. I have a little issue that no doubt stems from me not understanding the GHC API well, and I would be grateful for any light on the matter.
A meta-comment: the GHC API is much easier to grasp if you have a client at hand. In the case of IDE-like tools, my recommendation would be to look at the GHCi source - there is a wide range of overlap between what makes sense for GHCi and what makes sense for an IDE (think of GHCi as a commandline IDE;-). For your particular question: GHCi provides :info, which does manage to get (rough) source info for plain unqualified names, within a session context. So, starting from the source of the :info implementation might give you some hints (the command itself also helps you to find the GHC API source in question). Prelude> :set -package ghc Prelude> :info GHC.getName class Name.NamedThing a where ... Name.getName :: a -> Name.Name -- Defined in Name Prelude> :info Monad class Monad m where (>>=) :: m a -> (a -> m b) -> m b (>>) :: m a -> m b -> m b return :: a -> m a fail :: String -> m a -- Defined in GHC.Base instance Monad Maybe -- Defined in Data.Maybe instance Monad [] -- Defined in GHC.Base instance Monad IO -- Defined in GHC.Base Prelude> :info mapM mapM :: Monad m => (a -> m b) -> [a] -> m [b] -- Defined in Control.Monad Of course, those sources and GHCi commands aren't perfect (some of the code might still pre-date the API), and batch-processing an AST is different from an interactive read-eval-print loop, but some of the API was abstracted from GHCi and GHCi always needs to build with the current API version. Another side note: as you can see from the examples, you may not always have any source code to point to, in a typical GHC installation. That is why haskellmode for Vim links to the haddocks for those ids (somewhat oddly, the haddocks might come with HTML-ified sources, even when the original source is not installed..). Hope this helps, Claus

Claus:
scion-server mimics a GHCi command line, of sorts. scion-server is used very successfully to syntax-highlight the Eclipse editor, show a source's outline, provide type information when hovering over a name, and provide completions.
That's not the problem, per se. Let's say I'm hovering over a function that's imported by Data.Map. When resolved, the symbols appear to come from Ghc.Map (if memory serves correctly), which makes finding the correct "haddock" impossible.
-scooter
Sent from my Verizon Wireless BlackBerry
-----Original Message-----
From: "Claus Reinke"
Hello, I'm the maintainer for EclipseFP, which involves using the scion library and the GHC API to provide IDE functionality. I have a little issue that no doubt stems from me not understanding the GHC API well, and I would be grateful for any light on the matter.
A meta-comment: the GHC API is much easier to grasp if you have a client at hand. In the case of IDE-like tools, my recommendation would be to look at the GHCi source - there is a wide range of overlap between what makes sense for GHCi and what makes sense for an IDE (think of GHCi as a commandline IDE;-). For your particular question: GHCi provides :info, which does manage to get (rough) source info for plain unqualified names, within a session context. So, starting from the source of the :info implementation might give you some hints (the command itself also helps you to find the GHC API source in question). Prelude> :set -package ghc Prelude> :info GHC.getName class Name.NamedThing a where ... Name.getName :: a -> Name.Name -- Defined in Name Prelude> :info Monad class Monad m where (>>=) :: m a -> (a -> m b) -> m b (>>) :: m a -> m b -> m b return :: a -> m a fail :: String -> m a -- Defined in GHC.Base instance Monad Maybe -- Defined in Data.Maybe instance Monad [] -- Defined in GHC.Base instance Monad IO -- Defined in GHC.Base Prelude> :info mapM mapM :: Monad m => (a -> m b) -> [a] -> m [b] -- Defined in Control.Monad Of course, those sources and GHCi commands aren't perfect (some of the code might still pre-date the API), and batch-processing an AST is different from an interactive read-eval-print loop, but some of the API was abstracted from GHCi and GHCi always needs to build with the current API version. Another side note: as you can see from the examples, you may not always have any source code to point to, in a typical GHC installation. That is why haskellmode for Vim links to the haddocks for those ids (somewhat oddly, the haddocks might come with HTML-ified sources, even when the original source is not installed..). Hope this helps, Claus _______________________________________________ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users

scion-server mimics a GHCi command line, of sorts. scion-server is used very successfully to syntax-highlight the Eclipse editor, show a source's outline, provide type information when hovering over a name, and provide completions.
That's not the problem, per se. Let's say I'm hovering over a function that's imported by Data.Map. When resolved, the symbols appear to come from Ghc.Map (if memory serves correctly), which makes finding the correct "haddock" impossible.
"Impossible" is such an ugly word;-) The problem you encounter is that the GHC API is still, to a large part, just an open window into what happens to be in GHC. Since GHC's aims as a compiler differ from those of IDEs, its exposed functionality will sometimes be too limited to serve your purposes (eg, if GHC knows where a function is defined, it doesn't need to know how it was imported, once it gets past error reporting). If you tie yourself too closely to GHC's view, some things you'd like to do in an IDE will _appear_ to be impossible. That is why I recommend looking into the GHCi sources, because GHCi's needs are closer to those of an IDE. I assume you mean things like Data.List.map being a re-exported GHC.List.map being a re-exported GHC.Base.map, and :info not knowing about the intended abstractions: Prelude> :i map map :: (a -> b) -> [a] -> [b] -- Defined in GHC.Base You can actually get information about possible import paths via :browse! Prelude> :m +Data.List Prelude Data.List> :grep map|imported :browse! -- imported via Data.List mapAccumL :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y]) mapAccumR :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y]) -- imported via Data.List, Prelude map :: (a -> b) -> [a] -> [b] (:browse! is standard GHCi, :grep is non-standard, just to filter :browse! output). So the :browse! command seems to be able to find more of the information you want. haskellmode for Vim, on the other hand, has long provided haddock lookup, and will offer you a menu of possible destinations when your cursor is over 'map'. This menu is built from an index of Haddock entries, which is extracted from installed Haddock documentation. Nothing impossible about that, just ugly: so far, the index is scraped from Haddock's HTML index files. That route breaks occasionally (recent Haddock HTML changes, ghc-pkg listing wrong Haddock paths, ..; I'm about to publish updated scraping code for GHC-7.0.1's Haddock..). To get something less ugly, I'm currently recoding the extraction by using Haddock's API and .haddock files (that'll still break when the API changes, also there is a pending bug about ghc-pkg, cabal, and haddock disagreeing about filepath formats, meaning that .haddock files aren't found on Windows). I assume that code will be useful to other Haskell IDEs, though it is mostly exposing Haddock's internal ability to build an index from .haddock files, which I'd like to see exposed in Haddock's less-than-well-known API: http://trac.haskell.org/haddock/ticket/157 Claus

Claus:
Respectfully, "No duh!" as schoolkids here in the US like to say when someone points out the obvious to them.
And "impossible" is the right word since the predicate evaluates to a boolean. Since false is the outcome, "impossible" refers correctly to the status of fetching the documentation.
Yes, we've been looking at the GHC sources. Why else would the question be posed with regard to "is there a better way of doing this?" Personally, I've had my fun re-implementing cabal package reading, and recreating someone else's work is counterproductive.
-scooter
Sent from my Verizon Wireless BlackBerry
-----Original Message-----
From: "Claus Reinke"
scion-server mimics a GHCi command line, of sorts. scion-server is used very successfully to syntax-highlight the Eclipse editor, show a source's outline, provide type information when hovering over a name, and provide completions.
That's not the problem, per se. Let's say I'm hovering over a function that's imported by Data.Map. When resolved, the symbols appear to come from Ghc.Map (if memory serves correctly), which makes finding the correct "haddock" impossible.
"Impossible" is such an ugly word;-) The problem you encounter is that the GHC API is still, to a large part, just an open window into what happens to be in GHC. Since GHC's aims as a compiler differ from those of IDEs, its exposed functionality will sometimes be too limited to serve your purposes (eg, if GHC knows where a function is defined, it doesn't need to know how it was imported, once it gets past error reporting). If you tie yourself too closely to GHC's view, some things you'd like to do in an IDE will _appear_ to be impossible. That is why I recommend looking into the GHCi sources, because GHCi's needs are closer to those of an IDE. I assume you mean things like Data.List.map being a re-exported GHC.List.map being a re-exported GHC.Base.map, and :info not knowing about the intended abstractions: Prelude> :i map map :: (a -> b) -> [a] -> [b] -- Defined in GHC.Base You can actually get information about possible import paths via :browse! Prelude> :m +Data.List Prelude Data.List> :grep map|imported :browse! -- imported via Data.List mapAccumL :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y]) mapAccumR :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y]) -- imported via Data.List, Prelude map :: (a -> b) -> [a] -> [b] (:browse! is standard GHCi, :grep is non-standard, just to filter :browse! output). So the :browse! command seems to be able to find more of the information you want. haskellmode for Vim, on the other hand, has long provided haddock lookup, and will offer you a menu of possible destinations when your cursor is over 'map'. This menu is built from an index of Haddock entries, which is extracted from installed Haddock documentation. Nothing impossible about that, just ugly: so far, the index is scraped from Haddock's HTML index files. That route breaks occasionally (recent Haddock HTML changes, ghc-pkg listing wrong Haddock paths, ..; I'm about to publish updated scraping code for GHC-7.0.1's Haddock..). To get something less ugly, I'm currently recoding the extraction by using Haddock's API and .haddock files (that'll still break when the API changes, also there is a pending bug about ghc-pkg, cabal, and haddock disagreeing about filepath formats, meaning that .haddock files aren't found on Windows). I assume that code will be useful to other Haskell IDEs, though it is mostly exposing Haddock's internal ability to build an index from .haddock files, which I'd like to see exposed in Haddock's less-than-well-known API: http://trac.haskell.org/haddock/ticket/157 Claus

Simon, thanks for the tips! I have changed the code to use nameModule_maybe
and I've verified that using that on a function imported through a qualified
import works.
Claus, Scott, the redirection from one standard package to a GHC package
wasn't my issue. We're in an IDE that uses GHC, so redirecting to the GHC
page instead of the Prelude page is not really an issue, it may just startle
some users. GHCi does the same:
Prelude> :info map
map :: (a -> b) -> [a] -> [b] -- Defined in GHC.Base
Prelude> :info Prelude.map
map :: (a -> b) -> [a] -> [b] -- Defined in GHC.Base
But I still would like to find a workaround to be able to jump to the
definition even after the type checking rewrite Simon explains, in GHC
6.10/12. I'll keep poking on how to get from that lambda function to the
real function it calls.
Thanks to all,
JP
On Thu, Nov 18, 2010 at 2:36 PM,
Claus:
Respectfully, "No duh!" as schoolkids here in the US like to say when someone points out the obvious to them.
And "impossible" is the right word since the predicate evaluates to a boolean. Since false is the outcome, "impossible" refers correctly to the status of fetching the documentation.
Yes, we've been looking at the GHC sources. Why else would the question be posed with regard to "is there a better way of doing this?" Personally, I've had my fun re-implementing cabal package reading, and recreating someone else's work is counterproductive.
-scooter Sent from my Verizon Wireless BlackBerry
-----Original Message----- From: "Claus Reinke"
Date: Thu, 18 Nov 2010 10:53:05 To: ; Subject: Re: Using the GHC API: pretty printing with qualified names scion-server mimics a GHCi command line, of sorts. scion-server is used very successfully to syntax-highlight the Eclipse editor, show a source's outline, provide type information when hovering over a name, and provide completions.
That's not the problem, per se. Let's say I'm hovering over a function that's imported by Data.Map. When resolved, the symbols appear to come from Ghc.Map (if memory serves correctly), which makes finding the correct "haddock" impossible.
"Impossible" is such an ugly word;-)
The problem you encounter is that the GHC API is still, to a large part, just an open window into what happens to be in GHC. Since GHC's aims as a compiler differ from those of IDEs, its exposed functionality will sometimes be too limited to serve your purposes (eg, if GHC knows where a function is defined, it doesn't need to know how it was imported, once it gets past error reporting).
If you tie yourself too closely to GHC's view, some things you'd like to do in an IDE will _appear_ to be impossible. That is why I recommend looking into the GHCi sources, because GHCi's needs are closer to those of an IDE.
I assume you mean things like Data.List.map being a re-exported GHC.List.map being a re-exported GHC.Base.map, and :info not knowing about the intended abstractions:
Prelude> :i map map :: (a -> b) -> [a] -> [b] -- Defined in GHC.Base
You can actually get information about possible import paths via :browse!
Prelude> :m +Data.List Prelude Data.List> :grep map|imported :browse!
-- imported via Data.List mapAccumL :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y]) mapAccumR :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y]) -- imported via Data.List, Prelude map :: (a -> b) -> [a] -> [b]
(:browse! is standard GHCi, :grep is non-standard, just to filter :browse! output). So the :browse! command seems to be able to find more of the information you want.
haskellmode for Vim, on the other hand, has long provided haddock lookup, and will offer you a menu of possible destinations when your cursor is over 'map'. This menu is built from an index of Haddock entries, which is extracted from installed Haddock documentation.
Nothing impossible about that, just ugly: so far, the index is scraped from Haddock's HTML index files. That route breaks occasionally (recent Haddock HTML changes, ghc-pkg listing wrong Haddock paths, ..; I'm about to publish updated scraping code for GHC-7.0.1's Haddock..).
To get something less ugly, I'm currently recoding the extraction by using Haddock's API and .haddock files (that'll still break when the API changes, also there is a pending bug about ghc-pkg, cabal, and haddock disagreeing about filepath formats, meaning that .haddock files aren't found on Windows).
I assume that code will be useful to other Haskell IDEs, though it is mostly exposing Haddock's internal ability to build an index from .haddock files, which I'd like to see exposed in Haddock's less-than-well-known API:
http://trac.haskell.org/haddock/ticket/157
Claus
_______________________________________________ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
-- JP Moresmau http://jpmoresmau.blogspot.com/

OK, I have fixed my problem, without forcing all my users to upgrade to GHC 7: using the renamed source instead of the typechecked source gives me the properly qualified name. I hope that won't cause other problems but for the moment everything looks fine (functions, constructors, with type classes or not, with qualified imports all seem to work). Thanks everybody for the help! -- JP Moresmau http://jpmoresmau.blogspot.com/
participants (5)
-
Claus Reinke
-
JP Moresmau
-
scooter.phd@gmail.com
-
Simon Peyton-Jones
-
Thomas Schilling