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
:
>>> :browse Data.Char
digitToInt :: Char -> Int
isLetter :: Char -> Bool
isMark :: Char -> Bool
isNumber :: Char -> Bool
isSeparator :: Char -> Bool
[...and many more lines]
or
>>> :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:
>>> :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
:
>>> :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:
>>> :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
:
>>> :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
>>> :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 a
s, and produces another
list of a
s. 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
>>> 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
.