Almost every module in our code base has imports such as:
import qualified Data.Map as Map import qualified Data.Set as Set import qualified Data.Text as Text
I would like to define a local prelude so that Map
, Set
and Text
are available to the modules importing that prelude. Apparently there is no way to do that in Haskell. So I am wondering how do people solve this problem in large Haskell code bases.
The syntax for importing modules in a Haskell script is import <module name>. This must be done before defining any functions, so imports are usually done at the top of the file. One script can, of course, import several modules. Just put each import statement into a separate line.
A qualified import allows using functions with the same name imported from several modules, e.g. map from the Prelude and map from Data.
I'm going to answer this question, interpreted as literally as possible:
How do people solve this problem in large Haskell code bases?
Answer: they write
import qualified Data.Map as Map import qualified Data.Set as Set import qualified Data.Text as Text
at the top of each module which needs Map
, Set
, and Text
.
In my experience, managing imports is not a significant part of the difficulty of working with large codebases. The effort of jumping to the import list and adding a line for Data.Map
when you discover you need it is absolutely swamped by the effort of finding the right place in the codebase to make changes, knowing the full breadth of the codebase so you don't duplicate efforts, and finding ways to test small chunks of a large application in isolation.
Compared to the proposed alternative in the other answer (CPP), this way also has some technical advantages:
Foo.bar
as an identifier somewhere, I can use my text editor's regex search to find out what import line made the Foo
namespace available without fancy additions to include #include
d files. If I want to find all the files that depend on Some.Fancy.Module
, I can learn that by grepping for Some.Fancy.Module
. Build systems that do change detection don't need to know about the extra .h
file when computing which files to watch. And so forth.One solution is to define the import list in a CPP header.
N.B.: This answer is just to show what is technically possible; Daniel Wagner's answer is generally the better alternative.
For a package-level example:
my-pkg/ my-pkg.cabal include/imports.h src/MyModule.hs ...
include/imports.h
:
import Control.Applicative import Data.Maybe import Data.Char
In my-pkg.cabal
, components (library
, executable
, test
, ...) have a include-dirs
field (that in turn correspond to some GHC option):
library ... include-dirs: include
Then you can use that header in any module:
{-# LANGUAGE CPP #-} module MyModule where #include "imports.h" -- your code here mymaybe = maybe
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With