A surprising feature of Haskell is that by writing an explicit import of the special Prelude module the implicit import Prelude will be suppressed! You can even do the extreme of hiding all exports:

module M where import Prelude () one :: Int

one = 1

and as you may expect this will rightly cause a compile failure:

M.hs:5:8: error:

Not in scope: type constructor or class ‘Int’

Perhaps you want to add ‘Int’ to the import list in the import of

‘Prelude’ (M.hs:3:1-17).

|

5 | one :: Int

| ^^^

There’s multiple ways to resolve this including following GHC’s advice and adding Int to the import by using import Prelude (Int) . Or we could use qualified imports as from this point on the Prelude module behaves like any other module:

module M where import qualified Prelude as Pre one :: Pre.Int

one = 1 -- interestingly NOT `Pre.1`

With this in mind let’s see what a more minimalist Prelude could look like and impose as a general rule that we shall only bring into scope things that are magic or otherwise special to the language:

module Prelude.Minimalist (module Prelude) where import Prelude

( -- The `Bool` type is wired into the if/then/else and

-- pattern guards syntactical elements

Bool(False, True), -- Primitive numeric types

Int, Integer, Float, Double, Rational, Word, -- We import the primitive typeclass names which are special

-- because they can be auto-derived for custom types

Eq, Ord, Enum, Bounded, Show, Read, -- These two are special because of number literals

Num, Fractional, -- These are special because of `do`-desugaring

Functor, Applicative, Monad, return, -- These are magic primitives

seq, error, -- The IO monad is special and it's required by the

-- type-signature of `main :: IO ()`

IO

)

Some of the things that were intentionally left out:

() or [] or (,) or -> etc as these seem to be built-in syntax in GHC and you can’t control their scope

or or or etc as these seem to be built-in syntax in GHC and you can’t control their scope Other Numeric classes as they are not referenced by desugaring

otherwise because there’s nothing magic about it and it’s merely a redundant synonym of True : otherwise = True

because there’s nothing magic about it and it’s merely a redundant synonym of : Types such as Maybe or Either which are not wired into the language syntax

or which are not wired into the language syntax IO operations from System.IO

And now we can use the module above from another module like so

module MyMod where import Prelude.Minimalist

import Prelude () -- suppress default Prelude one :: Int

one = 1 pairM :: Monad m => m a -> m b -> m (a,b)

pairM ma mb = do

a <- ma

b <- mb

return (a,b)

And if you need to bring in more names from the Prelude module you can do so by simply importing them explicitly like so

import Prelude.Minimalist

import Prelude (Num(..), otherwise)

or you can use a qualified import

import Prelude.Minimalist

import qualified Prelude as Pre two :: Integer

two = 1 Pre.+ 1

or you can combine both depending on your taste.