Hoogle
Note: You may want to skip this section and return to it later when you understand basic Haskell syntax better.
Hoogle makes programming in Haskell a breeze once you understand the language basics. It is a search engine over the thousands of packages available on Hackage. Open a web browser and enter the URL hoogle.haskell.org (or click here). You should see a web page that looks something like this:
You can now enter the name of a function whose documentation you want to
access, say the digitToInt
function:
This tells you that digitToInt
has the type Char -> Int
. Even if you don't
know the syntax for Haskell types yet, it is not hard to guess that this means
that this function converts a Char
acter to an Int
eger. You can click on
the function to be taken to its detailed documentation:
The green text below the function signature on the previous page listing the
search results tells us useful additional information. It says that this
function is defined in the Data.Char
module, so you need to import this
module if you want to use the digitToInt
function:
>>> import Data.Char
>>> digitToInt '9'
9
The Data.Char
module is part of the base
package, which is essentially
Haskell's standard library and is preinstalled. Other modules may be part of
third-party packages. If you want to use those modules, you have to change the
Haskell Stack configuration of your program so that these third-party packages
are installed. We'll talk about management of packages in the Haskell Stack
later. A function isn't necessarily defined in only one module or package.
For example, the next package and module on the same line says that the
RIO.Char.Partial
module in the rio
package also defines a digitToInt
function.
So that's all basic information about functions that you would expect any basic API documentation to provide, and it's nice but not earth-shattering that we have a search engine like Hoogle to search for functions with various names across all packages available on Hackage. What's really cool is that we can search for functions on Hoogle even if we don't know their names.
Let's say we are looking for a function that takes a list of elements of type
a
. Haskell's syntax for such a list is [a]
. We want to partition this
list into two sublists, the first containing the elements that satisfy some
condition, the second containing the elements that do not satisfy the
condition. The return type should therefore be a pair of lists, again
containing elements of type a
. Haskell's syntax for this is ([a], [a])
.
We test whether a given element of type a
satisfies the condition we
are interested in using a function that returns True
if the element satisfies
the condition, and False
otherwise. The type of such a function is a ->
Bool
—it maps an element of type a
to a Boolean value. Now if we want to
have a function that allows us to partition a list of a
s into two lists based
on some condition, we need to provide the condition, a function of type a ->
Bool
, and the input list, of type [a]
as arguments to the function, and the
return value should be a pair of lists of type ([a], [a])
. The Haskell type
signature of such a function is (a -> Bool) -> [a] -> ([a], [a])
. The arrows
separate function argument types and the return type from each other. So this
function takes a function of type a -> Bool
as its first argument, a list of
type [a]
as its second argument, and it returns a pair of lists.
We can simply type this type signature into Hoogle, and it will give us a list of functions with this type signature that it finds.1
In this case, the third function in the result list, unsurprisingly called
partition
, is the one we are looking for. You can verify this by clicking on
its documentation. Again, the green text after the function signature tells us
that we need to import the module Data.List
if we want to use this function,
and that we do not need to install any additional packages because this module
is part of the base
package.
>>> import Data.List
>>> partition even [1,2,3,4,5,6]
([2,4,6],[1,3,5])
Do you need to guess the argument order of the function you're looking for
correctly? Maybe the implementor of the function thought that it would be
better to provide the list to be partitioned as the first argument and the
condition used to partition this list as the second argument. The resulting
type signature would be [a] -> (a -> Bool) -> ([a], [a])
. As it turns out,
Hoogle is smart enough to find all functions whose arguments match the given
types, in any order. Try it out. Search for this permuted function signature
and see that you'll once again get partition
as one of the hits.
I will not talk about Hoogle in the remainder of this book anymore. However, remember that you have this extremely useful tool at your disposal whenever you need to figure out whether there already exists a function that does exactly what you want to do.
-
You may wonder whether it is important that we used
a
as the type variable here. It is not. You can try searching for a function of type(b -> Bool) -> [b] -> ([b], [b])
or(t -> Bool) -> [t] -> ([t], [t])
, and you will get the same search results. After all,a
is a type variable and is therefore completely equivalent to the variableb
ort
. ↩