Skip to content

Listing the Contents of Modules

While we haven't talked about modules much yet, I mentioned the Data.Char and Data.List modules that are part of the standard library several times already. It may be helpful to find out what functions, types, and type classes are defined in these modules. The best way to do this is often to search for Data.Char or Data.List on Hoogle. This gives you a nicely organized overview of the different functions defined in these modules, along with their documentation. For a quick peek from within GHCi, without any documentation, we have :browse:

GHCi
>>> :browse Data.Char
digitToInt :: Char -> Int
isLetter :: Char -> Bool
isMark :: Char -> Bool
isNumber :: Char -> Bool
isSeparator :: Char -> Bool
[...and many more lines]

or

GHCi
>>> :browse Data.List
Data.List.isSubsequenceOf :: Eq a => [a] -> [a] -> Bool
(!!) :: [a] -> Int -> a
(++) :: [a] -> [a] -> [a]
(base-4.15.1.0:Data.OldList.\\) :: Eq a => [a] -> [a] -> [a]
all :: Foldable t => (a -> Bool) -> t a -> Bool
[...and many more lines]

Exercise

Which type class defines integer division operators such as div and mod? Which type class defines fractional division ((/))? Which other operations do they define? Find out from within GHCi using :info.

Solution

div is defined in the Integral type class:

GHCi
>>> :info div
type Integral :: * -> Constraint
class (Real a, Enum a) => Integral a where
  ...
  div :: a -> a -> a
  ...
    -- Defined in ‘GHC.Real’
infixl 7 `div`

This class also provides functions quot, rem, mod, quotRem, divMod, and toInteger:

GHCi
>>> :info Integral
type Integral :: * -> Constraint
class (Real a, Enum a) => Integral a where
  quot :: a -> a -> a
  rem :: a -> a -> a
  div :: a -> a -> a
  mod :: a -> a -> a
  quotRem :: a -> a -> (a, a)
  divMod :: a -> a -> (a, a)
  toInteger :: a -> Integer
  {-# MINIMAL quotRem, toInteger #-}
    -- Defined in ‘GHC.Real’
instance Integral Word -- Defined in ‘GHC.Real’
instance Integral Integer -- Defined in ‘GHC.Real’
instance Integral Int -- Defined in ‘GHC.Real’

(/) is defined in the Fractional type class:

GHCi
>>> :info (/)
type Fractional :: * -> Constraint
class Num a => Fractional a where
  (/) :: a -> a -> a
  ...
    -- Defined in ‘GHC.Real’
infixl 7 /

This class also provides functions recip and fromRational:

GHCi
>>> :info Fractional
type Fractional :: * -> Constraint
class Num a => Fractional a where
  (/) :: a -> a -> a
  recip :: a -> a
  fromRational :: Rational -> a
  {-# MINIMAL fromRational, (recip | (/)) #-}
    -- Defined in ‘GHC.Real’
instance Fractional Float -- Defined in ‘GHC.Float’
instance Fractional Double -- Defined in ‘GHC.Float’

Exercise

If you load the MergeSort.hs file we used earlier in this chapter using :load MergeSort.hs, what does :info tell you about the mergeSort function?

Solution
GHCi
>>> :load MergeSort.hs
[1 of 1] Compiling Main             ( MergeSort.hs, interpreted )
Ok, one module loaded.
>>> :info mergeSort
mergeSort :: Ord a => [a] -> [a]    -- Defined at MergeSort.hs:2:1

This says that the mergeSort function is defined in MergeSort.hs. It takes an argument of type [a], a list of as, and produces another list of as. However, a cannot be just any type. It must be an instance of the Ord type class: values of type a must be comparable.

Exercise

What does :info tell you about an interactively defined value? For example, define x = 5 at the GHCi prompt. Then get information about x using :info x.

Solution
GHCi
>>> x = 5
>>> :info x
x :: Num p => p     -- Defined at <interactive>:3:1

In this case, the type of x is Num p => p. We discussed before why: Given no context to narrow down the type further, GHCi cannot determine more than that x must have a number type. GHCi can deduce this much because we are assigning 5 to x, which is a number.

Moreover, :info tells us that x was defined interactively, not in any module of the standard library or in any file we may have loaded: -- Defined at <interactive>:3:1.