What is the default path of the source of Haskell modules (Prelude, etc.)? - haskell

I want to browse the source of the installed Haskell modules on my machine.
What is the default search path of Haskell's import?

So there's a bit of an impedance mismatch here, since packages are generally installed as binaries (though the most popular way to get the binaries is to build from source). Still, it's not too bad. The rough plan will be to map from module name to package/version pair, then ask cabal to unpack a copy of that version of the package.
Let's say I wanted to read the source for Data.Text. Then:
% ghc-pkg find-module Data.Text
/usr/local/lib/ghc-8.2.1/package.conf.d
(no packages)
/home/dmwit/.ghc/x86_64-linux-8.2.1/package.conf.d
text-1.2.2.2
% cabal unpack text-1.2.2.2
Unpacking to text-1.2.2.2/
You will now have a text-1.2.2.2 directory containing the source for the text package -- including a file in text-1.2.2.2/Data/Text.hs that contains the source for the Data.Text module.

Related

How do you import a Haskell module that was installed using Cabal?

I installed the timezone-series Haskell module using cabal install timezone-series-0.1.5.1.
I then defined a module named Main.hs that starts with:
import Data.Time.LocalTime.TimeZone.Series -- from timezone-series-0.1.5.1
when I run ghc Main.hs, GHC throws the following error:
/home/ubuntu/Main.hs:2:1: error:
Failed to load interface for ‘Data.Time.LocalTime.TimeZone.Olson’
I tried explicitly including the cabal directory in GHC's search path using:
ghc -i/home/ubuntu/.cabal/lib/x86_64-linux-ghc-8.0.2/timezone-olson-0.2.0-KqRNJj3zomR7zz2Yx6P5Oq/ Main.hs
This resulted in the correct path being searched, but GHC is only looking for files ending in the suffix ".hs":
Locations searched:
...
/home/ubuntu/.cabal/lib/x86_64-linux-ghc-8.0.2/timezone-olson-0.2.0-KqRNJj3zomR7zz2Yx6P5Oq/Data/Time/LocalTime/TimeZone/Series.hs
/home/ubuntu/.cabal/lib/x86_64-linux-ghc-8.0.2/timezone-olson-0.2.0-KqRNJj3zomR7zz2Yx6P5Oq/Data/Time/LocalTime/TimeZone/Series.lhs
/home/ubuntu/.cabal/lib/x86_64-linux-ghc-8.0.2/timezone-olson-0.2.0-KqRNJj3zomR7zz2Yx6P5Oq/Data/Time/LocalTime/TimeZone/Series.hsig
/home/ubuntu/.cabal/lib/x86_64-linux-ghc-8.0.2/timezone-olson-0.2.0-KqRNJj3zomR7zz2Yx6P5Oq/Data/Time/LocalTime/TimeZone/Series.lhsig
Cabal installed interface files instead however:
/home/ubuntu/.cabal/lib/x86_64-linux-ghc-8.0.2/timezone-olson-0.2.0-KqRNJj3zomR7zz2Yx6P5Oq/Data/Time/LocalTime/TimeZone/Olson.hi
From line 318 of GHC's source code it looks like GHC ignores "*.hi" files unless it is called in single-shot mode (with the -c flag). Is this correct? (See: https://github.com/ghc/ghc/blob/67a5a91ef5e61f3b3c84481d8a396ed48cd5d96e/compiler/GHC/Unit/Finder.hs)
How can I get GHC to import this module?
An help will be greatly appreciated!
My suggested ways of installing packages in order of my preference:
Make a cabal package and add timezone-series you want to install to the build-depends field as described in the cabal manual.
Use the experimental cabal-env tool to basically automate the process of point 3 below, but then with the global environment. This makes a new build-plan every time you install a new package, so it is like removing the package environment and building it again with all the old packages and the new package added to it. You can add specific constraints like this: cabal-env "timezone-series == 0.1.5.1".
Install a package into local package environment with cabal --package-env . --lib timezone-series. You can add as many packages as you want after the --lib option to install more than one package. If you later want to use a different set of packages simply remove the .ghc.environment.* file that is generated and rerun the installation with a new set of packages. GHC will automatically use these package environment files that are in the current or parent directories. You can specify specific constraints with the --constraint option like this: --constraint "timezone-series == 0.1.5.1".
Use cabal install --lib timezone-series to install it directly into the global environment (~/.ghc/x86_64-linux-8.0.2/environments/default), this will fail if a conflicting package was installed earlier. When you run into errors you can remove that package environment and try again.
Finally, I want to note that GHC 8.0.2 is quite old, so I would advise you to upgrade if you don't have a specific reason for using that version.

Cabal cannot find locally sourced (yet correctly installed) packages

I recently upgraded to Cabal 3.2 (and GHC 8.10) and I am running into some major issues that make some of my project non-buildable anymore...
Thorough description of the problem
Here is a minimal (not) working configuration that fails every time:
I start off with a clean Cabal configuration (by deleting ~/.cabal); the reason for that will appear later in the post. I run cabal update to recreate the .cabal directory and to ensure Cabal is working.
I create a project (let's call it test1) using cabal init. This is a library project with one exposed module (conveniently named Test1) that exports some dummy function foo. I run cabal build, then cabal install --lib; everything is running smooth, so far so good.
Just to be sure, I leave the project directory and fire up GHCi. I type in :m Test1 to load the module I created earlier, and it works! I can type in foo ... and see my function executed. Also, I list the content of ~/.cabal/store/ghc-8.10.xxx and see that the test1-xxx directory is there.
I then create a new project, test2, still using cabal init. This time, I configure it to be an executable, and I add test1 as a dependency (using the build-depends field). But this time when I run cabal build, I run into some issue:
~/projects/haskell/test2> cabal build
Resolving dependencies...
cabal: Could not resolve dependencies:
[__0] trying: test2-0.1.0.0 (user goal)
[__1] unknown package: test1 (dependency of test2)
[__1] fail (backjumping, conflict set: test1, test2)
After searching the rest of the dependency tree exhaustively, these were the
goals I've had most trouble fulfilling: test2, test1
It seems to me like package test1 cannot be found, however I can access it from GHCi (and GHC for that matters) and it is present in ~/.cabal/store...
But unfortunately there is more.
I create a third project, test3. This is a library, and it depends on nothing else than base (so in particular it does not depend on test1). The lib exposes one module, Test3, with one function exported, bar. I run cabal build, no problem here. But when I want to install test3 with cabal install --lib I run into some errors:
~/projects/haskell/test3> cabal install --lib
Wrote tarball sdist to
/home/<user>/projects/haskell/test3/dist-newstyle/sdist/test3-0.1.0.0.tar.gz
Resolving dependencies...
cabal: Could not resolve dependencies:
[__0] unknown package: test1 (user goal)
[__0] fail (backjumping, conflict set: test1)
After searching the rest of the dependency tree exhaustively, these were the
goals I've had most trouble fulfilling: test1
It seems that it cannot find test1, although it has been installed correctly; may be this is a remnant of the failed build of test2 though...
Just to be sure, I fire up GHCi and type in :m Test3, but GHCi tells me that it cannot find module Test3 (and even suggests this is a typo and I was meaning Test1), showing that test3 indeed did not get installed, although it got successfully built...
Okay there is one more quirk to this whole situation: I create once again a new project with cabal init, called test4, which is an executable that (again) depends on nothing else than base. I keep the default Main.hs (that just prints "Hello, Haskell!"). I run cabal build: no problem. Then I run cabal install and... No problem either? I run test4 in a random location and it fires up the executable, printing "Hello, Haskell!" in the terminal...
And there is one last thing: I go to some random location and I run cabal install xxx --lib where xxx is a library package available on Hackage (for example xml) and:
~> cabal install xml --lib
Resolving dependencies...
cabal: Could not resolve dependencies:
[__0] unknown package: test1 (user goal)
[__0] fail (backjumping, conflict set: test1)
After searching the rest of the dependency tree exhaustively, these were the
goals I've had most trouble fulfilling: test1
This is the reason why I need to nuke .cabal regularly... Right now I seem to be in some kind of stale state where I cannot install any library anymore.
Technical configuration and notes
I am running Cabal 3.2.0.0 and GHC 8.10.0.20200123. I installed them from the hvr/ghc PPA, and I made sure there are no other versions of those tools anywhere on my computer.
Just as a note, I am running Ubuntu 18.04.4 LTS (with XFCE so XUbuntu to be exact). Everything else (seem to be like it) is up to date.
Last thing, regarding the *.cabal files I use for building, they are pretty much the ones generated by cabal init, except I switch executable xxx for library in the case of libraries, and I simply add a exposed-modules field for exposing modules for the libraries (so Test1 for test1 and Test3 for test3 respectively). I also use build-depends in test2 to make the project depend on test1. Apart from that, they are pretty much left untouched.
Notes and thoughts
I must confess that I am new to Cabal 3; until last week I was using Cabal 1 (because I never bothered to update it; yes I know this is bad). With Cabal 1 I did not have any problem whatsoever, and I was perfectly able to install a package from local sources and depend on it in other projects...
I feel like I am doing something wrong; maybe am I not using the correct Cabal commands? I saw somewhere something about cabal new-build and cabal new-install but it does not seem to do anything more than cabal build and cabal install, at least in my case. I also wanted to investigate sandboxes but it seems that has disappeared since version 2 of Cabal.
There is also a slight possibility this is a Cabal bug, but I don't find any relevant issue on the bug tracker that may be related to my problem...
What do you think about this? What am I doing wrong? Do you see any alternative or possible fix?
Thanks a lot!
GHC environment files
A GHC installation comes with a certain number of packages out-of-the box. base is one of them but there are others, for example text. If you install GHC alone (no cabal or stack) and open ghci, it should let you import Data.Text without problems.
What if you want GHC or ghci to be aware of other compiled packages present in your filesystem? You can point GHC to additional package databases using command-line flags, but there's also the concept of package environment files.
Environments are plain text files that contain a list of package-related GHC flags. There might be a global environment at ~/.ghc/$ARCH-$OS-$GHCVER/environments/default, and there might also exist local environments which only affect GHC and ghci commands invoked inside the same folder. The exact rules for search are described in the GHC User Guide.
What does cabal install --lib actually do?
By default, it modifies the global environment file, so that GHC and ghci can now find that library. That's why point 3) worked. The actual compiled binaries of the library still reside in the cabal store though.
We can also create local environment files. For example cabal install sop-core --lib --package-env . will create the environment file .ghc.environment.xxx in the current folder, and the library will be available to ghc and ghci when they are invoked there.
Why isn't test1 available for test2?
Modern cabal makes a distinction between local packages and external packages.
local packages is the set of packages you are developing together in a project, being edited, recompiled and changed repeatedly. They are built "inplace" and not seen outside the project. They can depend on each other.
external packages are dependencies from build-depends: whose source code is downloaded from a package repository and which, when compiled, are put in the cabal store so that other Cabal projects might make use of them without re-compiling.
The list of local packages and other project-level configuration details are specified in a cabal.project file. But you don't need one if you work on a single isolated package; the default list of packages is simply ./*.cabal.
cabal wants to completely control the build environment of local packages, and will ignore the global environment file. In your case, you'll have to make test1 and test2 local packages in the same project (likely the best option) or publish test1 and treat it as an external package.
Note that "cabal project" is a concept relevant only during development. Packages are published independently, there are no "projects" in Hackage or other repositories, just packages.
What if I want to treat test1 as external without publishing it to Hackage?
You will have to set up a local package repository, basically a non-public Hackage.
You can tell Cabal about additional package repositories in the Cabal configuration file, that is, the file that configures cabal itself. Its location is given in the last line of cabal --help.
But how to set up the repository? The hackage-repo-tool can help with that.
Why did test3 fail? Why did further library installs fail?
That's weird, I have no idea why that happens. Did you by perchance delete the ~/.cabal folder between steps 3) and 5) ? What happens if you delete the global GHC environment file and try again?

Duplicate packages in Haskell environment?

I put this in a file (see bottom) and got the following error when loading it in ghci (i.e. start ghci then :l file):
7:13: error:
• Couldn't match expected type ‘network-uri-2.6.1.0#network-uri-2.6.1.0-7BN1tbB3iHQ2XgvmqLAYph:Network.URI.URI’
with actual type ‘Network.URI.URI’
NB: ‘Network.URI.URI’
is defined in ‘Network.URI’
in package ‘network-uri-2.6.1.0#network-uri-2.6.1.0-80FpvaNUTSDFCPv0sSze40’
‘network-uri-2.6.1.0#network-uri-2.6.1.0-7BN1tbB3iHQ2XgvmqLAYph:Network.URI.URI’
is defined in ‘Network.URI’
in package ‘network-uri-2.6.1.0#network-uri-2.6.1.0-7BN1tbB3iHQ2XgvmqLAYph’
Have I somehow installed two slightly different versions of network-uri, or what is this? How do I resolve it?
I've hardly used cabal but tried cabal install --reinstall network-uri, went fine but problem persists.
File contents:
import Network.HTTP
import Network.URI (parseURI)
import Data.Maybe (fromJust)
myRequestURL = "http://www.virginia.edu/cgi-local/ldapweb"
myRequest :: String -> Request_String
myRequest query = Request {
rqURI = fromJust $ parseURI myRequestURL
, rqMethod = POST
, rqHeaders = [ mkHeader HdrContentType "text/html"
, mkHeader HdrContentLength $ show $ length body ]
, rqBody = body
}
where body = "whitepages=" ++ query
main :: IO ()
main = do
response <- simpleHTTP $ myRequest "poon"
putStrLn ""
EDIT Re-installed haskell-platform. After this, ghc-pkg list reports all packages to be under (?) /usr/lib/ghc/package.conf.d, and the program I tried to copy loads just fine.
EDIT 2 After running cabal install some-pkg, ghc-pkg list reports that the newly installed stuff is in another directory. Indeed, ~/.cabal/config specifies install dirs for user, as well as install dirs for global. How is all this supposed to be managed properly?
GHC understands the concept of package databases. Cabal manages multiple package databases. There's a system package database, and a user package database. When you compile something with Cabal V1, it uses the union of these package databases. This is a bit of a time bomb, because, as you see, GHC does not like it when you have multiple of the same package. When you issued cabal install network-uri, cabal decided to install one copy of that package into your user database, though you already had one in the system database. When you tried to use ghc, it picked up on the two copies and got confused. Because cabal does not support removing packages, your Haskell installation was pretty much borked, and you reinstalled. I believe you could have done a more conservative rm ~/.ghc, or, had you been really adventurous, used the low-level ghc-pkg command to edit the package database.
Now that you've reinstalled the Platform, I would heavily recommend never using cabal install again. It's old, it's broken, cabal itself tells you not to use it. If you're using the Platform, I think it has stack in it, which is a different build manager, based on Cabal, which is not prone to this kind of breakage. Or, you can just stick to the V2 series of cabal commands, which is what I prefer.
Cabal V2 does not directly support your usecase, where you install a package globally and compile a program against it. This is because doing so is fundamentally broken: global package databases really just don't work for GHC. What Cabal V2 does is install packages into your home directory, ~/.cabal/store. You then have to explicitly tell it which packages you want, and it will construct a package database that contains each required package, without any wonkiness. You can get a REPL with a certain set of packages by issuing (this will take you to a temporary directory; you may need to :cd yourself back.)
cabal v2-repl -b network-uri -b package2 -b etc
If you want to actually compile files with ghc with a set packages, you have to actually define a package with a .cabal file. Here's a stub .cabal file:
name: temporary-pkg
version: 0.0.0.0
build-type: Simple
cabal-version: >=2.0
executable main -- if there is no Main, say "library" instead of "executable <name>"
default-language: Haskell2010
main-is: Main.hs -- only valid in executable stanzas
hs-source-dirs: src -- source files go here
build-depends: base, network-uri, package2, etc -- packages go here
Create and enter a directory, place that in temporary-pkg.cabal, place your sources in src/, and you can issue stuff like cabal v2-build and cabal v2-repl and cabal v2-exec main, etc. cabal will go off and install dependencies from Hackage into ~/.cabal/store as needed. cabal v2-install is therefore not that useful here. In general, v2-installing libraries is unnecessary, but v2-installing packages with executables is useful. Again, for hygiene reasons, you have to list all the packages you are importing from, but you don't need to list their dependencies or anything insane like that.
Cabal V2 still doesn't support uninstalling packages, though the point is that should not be necessary. However, if you find ~/.cabal/store getting too large for your liking, you can just nuke it, and should be built back up as packages are requested.

GHC can not find installed module

My haskell installation can not find bytestring module installed by operating system
$ ghci
GHCi, version 7.6.3: http://www.haskell.org/ghc/ :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Prelude> :m +Data.ByteString.Lazy
<no location info>:
Could not find module `Data.ByteString.Lazy'
It is not a module in the current program, or in any known package.
But I have installed this module using yum:
$ rpm -ql ghc-bytestring
/usr/lib64/ghc-7.6.3/bytestring-0.10.0.2
/usr/lib64/ghc-7.6.3/bytestring-0.10.0.2/libHSbytestring-0.10.0.2-ghc7.6.3.so
/usr/share/doc/ghc-bytestring
/usr/share/doc/ghc-bytestring/LICENSE
What is wrong?
If this is happening, you should be able to figure out more via ghc-pkg list. This could happen, for example, if the binary package provided by your software repository was broken; ghc-pkg list would report that. In general, either GHC is not looking for packages in /usr/lib64/ghc-7.6.3/ or else that directory has a package.cache which was not updated to reflect the new package.
One thing that could cause GHC to look in the wrong place is if there are multiple GHCs on the machine: for example if which ghc reveals /usr/local/bin/ghc then you probably compiled GHC from source at some point and its packages are occupying some /usr/local/lib/ghc-7.6.3/package.conf.d/ folder, while your repository has installed /usr/bin/ghc which is looking in the folder you want.
Anyway, fixes: if the package.cache file exists and has a valid entry for the file, then you can run ghc -package-conf /path/to/package.cache ... to add those packages to your executable. If you have further problems, ghc -v ... is a great resource for debugging "which version of that package is being used here?" types of problems.
If the package.cache file does not exist then you've got a bigger problem, and probably the easiest way to move forward is to look for a directory under /home which appears on ghc-pkg list. Install the required package to that directory and GHC should pick up on it even though it doesn't understand these bigger contexts. You could also start working with a cabal sandbox of local packages to your project.
Situation here is similiar to C++ you have libraries used during dynamic linking stage and header used for compilation. In Fedora packages like ghc-bytestring are only libraries without headers. To install headers I had to install ghc-bytestring-devel package.
An example on Fedora 24:
server.hs:7:8:
Could not find module ‘Data.Text’
Perhaps you meant Data.Set (from containers-0.5.5.1)
Locations searched:
Data/Text.hs
Data/Text.lhs
So change to user root, then:
What packages are there?
# dnf search ghc|grep text
ghc-text.x86_64 : An efficient packed Unicode text type
ghc-boxes.x86_64 : 2D text pretty-printing library
ghc-pango.x86_64 : Binding to the Pango text rendering engine
ghc-css-text.x86_64 : CSS parser and renderer
ghc-hgettext.x86_64 : Haskell binding to libintl
ghc-attoparsec.x86_64 : Fast combinator parsing for bytestrings and text
ghc-text-devel.x86_64 : Haskell text library development files
ghc-blaze-textual.x86_64 : Fast rendering of common datatypes
ghc-css-text-devel.x86_64 : Haskell css-text library development files
ghc-hgettext-devel.x86_64 : Haskell hgettext library development files
ghc-blaze-textual-devel.x86_64 : Haskell blaze-textual library development files
So what's installed?
# rpm --query ghc-text
ghc-text-1.1.1.3-3.fc24.x86_64
# rpm --query ghc-text-devel
package ghc-text-devel is not installed
So let's install the devel package.
# dnf install ghc-text-devel
Installed:
ghc-text-devel.x86_64 1.1.1.3-3.fc24
...and compilation succeeds after that.

Haskell Hidden Packages: Data.HashSet

I'd like to use Data.HashSet in Haskell. So I put import Data.HashSet at the beginning of my program. GHCi complains: Could not find module Data.HashSet.
My questions are:
How can I get Data.HashSet to work?
I've read somewhere that this is part of a hidden module or package. Why is the module hidden? Does "hidden" mean that I should not use it?
If I should not use it, is there a better alternative for a haskell data structure with a near-constant lookup time?
Data.HashSet is a module in the unordered-containers package, and also in the hashmap package. If you have either package installed,
import Data.HashSet
should work out of the box, since it is an exposed module of both packages. To install it (using unordered-containers, since that is the commonly used one),
cabal update
cabal install unordered-containers --dry-run
-- check that it wouldn't reinstall anything, if all's fine
cabal install unordered-containers

Resources