admin管理员组

文章数量:1402906

Another elementary question about using GHC: finding the package containing a module when using existing code. This question has been asked several times here, but none of the answers seem to really address this basic issue.

I expected that the answer would be to use hackage, but the search facility is peculiar or perhaps under-documented.

Example: I have

import System.Random

So I visit hackage and try to search for System.Random with the search packages facility. I get back mersenne-random-pure64, randfile and normaldistribution. But not the random package which is what I am expecting from past experience.

Searching with just Random, however, does return the random package among many others. Which may suggest that "." is some sort of meta-character. But what, and why is there no documentation?

Somewhere, I saw that the search was in a package's metadata without defining the term metadata. I downloaded the random package tarball and looked at the contents and "System.Random" was in the description field of random.cabal among other places, so why can't Hackage see it?

Or is there some other way to identify a package or packages containing a particular module?

Another elementary question about using GHC: finding the package containing a module when using existing code. This question has been asked several times here, but none of the answers seem to really address this basic issue.

I expected that the answer would be to use hackage, but the search facility is peculiar or perhaps under-documented.

Example: I have

import System.Random

So I visit hackage and try to search for System.Random with the search packages facility. I get back mersenne-random-pure64, randfile and normaldistribution. But not the random package which is what I am expecting from past experience.

Searching with just Random, however, does return the random package among many others. Which may suggest that "." is some sort of meta-character. But what, and why is there no documentation?

Somewhere, I saw that the search was in a package's metadata without defining the term metadata. I downloaded the random package tarball and looked at the contents and "System.Random" was in the description field of random.cabal among other places, so why can't Hackage see it?

Or is there some other way to identify a package or packages containing a particular module?

Share Improve this question edited Mar 22 at 21:14 reverish asked Mar 20 at 22:00 reverishreverish 531 silver badge4 bronze badges 4
  • 2 hoogle.haskell./… – Naïm Favier Commented Mar 20 at 22:23
  • The . in a module name is special only in that lexically it must separate chunks starting with capital letters. In every other way, it's just part of an opaque string. In particular, the hierarchy of namespaces that the documentation shows is a social understanding, not a technical concern. – Carl Commented Mar 21 at 4:30
  • 1 If you already have the appropriate package installed, you can use ghc-pkg find-module. I could have sworn there used to be a cabal search for the case where you don't have it installed, but it doesn't seem to exist any more (if it ever did). Unfortunate. It seems like a very reasonable feature request; cabal already has all the info it needs (e.g. you can see System.Random in cabal info random, even if random is not installed). – Daniel Wagner Commented Mar 21 at 15:31
  • I should have said that I tried ghc-pkg find-module right at the start, but as noted that is of no help. You have to have installed the "unknown" package first as noted. – reverish Commented Mar 22 at 12:14
Add a comment  | 

2 Answers 2

Reset to default 3

Here's an awful hack you can use:

cabal list | grep '^\*' | cut -d' ' -f2 | xargs cabal info 2>/dev/null \
  | grep '^\(\*\| *System\.Random$\)' | grep -B1 ' *System\.Random$' \
  | grep '^\*'

Explanation:

  • cabal list: show some basic info about every package cabal knows about
  • grep '^\*': keep only lines with a package name on them
  • cut -d' ' -f2: keep only the package name from each line; we now have a long list of packages
  • xargs cabal info 2>/dev/null: produce detailed information about each package, including their module lists; because cabal is invoked many times in the pipeline, any warnings or errors sent to stderr will get repeated many times, so we redirect those away every time except the first cabal list with 2>/dev/null
  • grep '^\(\*\| *System\.Random$\)': keep only lines that have a package name (^\*) or a module name that matches the pattern we like (^ *<pattern>$)
  • grep -B1 '^ *System\.Random$': -B1 says to keep one line before each match, which should be the package name that exposes the module that matched
  • grep '^\*': keep only the lines with package names (tossing the module names and some other diagnostic output from the previous grep)

Of course, if cabal could do the same thing itself, that would be much cleaner and probably much faster as well.

On my system, the pipeline above prints only the random package, which seems right to me. A more exciting search for Data.List shows that this can produce many results if there are such, listing base, base-noprelude, bizzlelude, bizzlelude-js, fay-base, haskell2010, haskell2020, liquid-base, rerebase, and safe-coupling. More packages than I expected export that module!

Compared to using hoogle, this uses a more complete initial package list (all of Hackage rather than all of Stackage) and gives you flexibility over whether you are searching for an exact module name (as above) or the prefix of a module hierarchy (drop the $ from the module patterns). However it is more fragile, possibly producing false positives if your module pattern matches some other part of the package information than the exported modules list, and is tightly coupled with details of cabal's current output format.

The usual approach is to search on Hoogle. A simple search for System.Random yields the module of that name in the random package as the first hit, plus other hits for the word "random" more generally that occur under the System hierarchy (not just modules, but classes and functions).

However, you can refine the search to search only for modules using a tag. So a search for module:System.Random also yields that module in the random package as the first hit, as well as some additional System.Random.* modules from other packages.

Update: The above refers to the Hoogle web site. To use a locally installed Hoogle, you'll need to install the Hoogle package (e.g., cabal install hoogle), generate a database (e.g., hoogle generate for a Stackage database), and launch a local web server on port 8080 (hoogle server) to get a full-featured interface. While there is a Hoogle command line interface, it seems rudimentary. As you mentioned in the comments hoogle module:System.Random will show "hits" without any package information, and while there's a semi-documented --info parameter that will dump additional information including the package name (hoogle --info module:System.Random), it inexplicably only displays information for the first search result. See this StackOverflow question for more.

本文标签: How do I find the Haskell package containing a particular moduleStack Overflow