Introduction

We’ll start with a basic overview to see what working with GHCi is like: how to run it, how to use commands, and how to read its output.

Starting GHCi

Assuming you already have a working installation of GHC on your machine, you should be able to open a GHCi session by typing ghci on the command line from any directory that can access GHC.Both of the major build tools, cabal and stack, have their own commands to open project-aware REPLs, but using those will not be our focus here. Further documentation is available here for cabal users and here for stack users. One benefit of using these is that opening a GHCi session from within a project directory using, e.g., stack repl, may load your Main module automatically and also make the GHCi session aware of the project’s dependencies.

$ ghci

Haskell expressions can then be typed directly at the prompt and immediately evaluated.

λ> 5 + 5
10

λ> "hello" ++ " world"
"hello world"

λ> let x = 5+5 ; y = 7 in (x * y)
70

GHCi will interpret the line as a complete expression. If you wish to enter multi-line expressions, you can do so with some special syntax.

λ> :{
 > let x = 5+5; y = 7
 > in
 > (x * y)
 > :}
70

Invoking GHCi with options

You can open GHCi with a file loaded from the command line by passing the filename as an argument. For example, this command loads the file fractal.hs into a new GHCi session:

$ ghci fractal.hs

If that module has dependencies other than the base library, though, they won’t be loaded automatically. We’ll cover bringing those into scope in a separate section, below.

You can also open GHCi with a language extension, for example, already turned on. For example,

$ ghci
<elided opening text>

λ> :type "julie"
"julie" :: [Char]

But if you pass it the -XOverloadedStrings flag, then that language extension will be enabled for that session.

$ ghci -XOverloadedStrings
<elided opening text>

λ> :type "julie"
"julie" :: Data.String.IsString p => p

A great number of other GHC flags can be passed as arguments to ghci in this fashion. For the most part, we will cover those as they come up in other contexts, rather than attempting to list them all here.

Your GHCi configuration, if you have one, will be loaded by default when you invoke ghci. You can disable that with a flag:

$ ghci -ignore-dot-ghci

Packages

There are a few ways to bring modules and packages into scope in GHCi. One is using stack or cabal to open a project-aware REPL, which usually works well to bring the appropriate dependencies into scope. However, there are a few other options.

You can import modules directly in GHCi using import, just as you do at the top of a file if your GHCi is already aware of the package the module comes from.

λ> :type bool

<interactive>:1:1: error: Variable not in scope: bool

λ> import Data.Bool

λ> :type bool
bool :: a -> a -> Bool -> a

All modules in base are fair game for importing, as are modules in a project-aware GHCi session or a GHCi session that has been invoked with the -package flag, thus loading the package into the session.

All the same import syntax is available for this, such as hiding and qualified.

The base package is always loaded by default into a GHCi session (as is the Prelude module, unless you have disabled that), but that’s not, of course, the case for many packages. However, your GHC installation came with a few packages that are available but not automatically loaded into new GHCi sessions. You can find out what you have available by running

$ ghc-pkg list

on the command line. You should see a list of all the packages that are installed and available. Modules from any of those listed packages can be directly imported, just as if they were in base. So, assuming your list includes containers, you can type import Data.Map or the like directly into your GHCi session, regardless of whether it’s one of your project’s dependencies – or if you even have a project going.

If you are using a stack or cabal REPL, then there may be many more packages in their local package lists that are available to new GHCi sessions. If you have previously opened a GHCi session with something like

$ stack repl --package QuickCheck

then stack will have installed QuickCheck and, if in the future you open a stack repl session but forget to pass the --package flag and then suddenly you realize you want to make QuickCheck available in this GHCi session, you can :set -package within GHCi to bring it into scope:

λ> :type property

<interactive>:1:1: error: Variable not in scope: property

λ> :set -package QuickCheck
package flags have changed, resetting and loading new packages...

λ> import Test.QuickCheck

λ> :type property
property :: Testable prop => prop -> Property

It’s really handy not to have to restart a GHCi session just to load a package you use frequently!

Commands

First let’s start with a couple of basics: you can use the up-arrow, down-arrow, and tab-complete in GHCi, so if you are already comfortable with these from your bash shell or what have you, you’ll enjoy this.

Furthermore, if you are in a GHCi session, shell commands can be made available using the :! GHCi command. For example, let’s say we’ve forgotten what directory we’re in and what files are in this directory, but we don’t want to quit GHCi to find out. No problem!

λ> :! pwd
/home/jmo

λ> :cd /home/jmo/haskell-projects

λ> :! ls
emily  fractal-sets  haskell-fractal  life  shu-thing  web-lesson4

Notice the :cd command doesn’t need the :!.

To quit a GHCi session, use :quit or :q.

GHCi commandsMuch of this course will be about GHCi commands. List of commands gives an overview of all of them, and several other lessons elaborate on specific commands of particular importance. all start with a colon (except import). They may all be abbreviated to just their first letter; however, if there is more than one command that starts with the same letter, such as :main and :module, it will default to reading that as whichever is more commonly used. When in doubt, type it out.

You can type :? for a complete listing of the GHCi commands.

What is it

GHCi assigns the name it to the last-evaluated expression. If you aren’t using :set +tWe will see :set +t and other uses of :set later in the page on the GHCi :set command. to automatically display types for expressions entered into or evaluated in GHCi, then you might not notice it until you see an error message that mentions it such as this one:

λ> max 5 _

<interactive>:76:7: error:
    • Found hole: _ :: a
      Where: ‘a’ is a rigid type variable bound by
               the inferred type of it :: (Ord a, Num a) => a
----------------------------------- ^^
               at <interactive>:76:1-7
    • In the second argument of ‘max’, namely ‘_’
      In the expression: max 5 _
      In an equation for ‘it’: it = max 5 _
------------------------- ^^

It isn’t always important or useful to recognize that GHCi has named the expression, but there’s at least one interesting thing about it that you may find useful. Here’s a clue:

λ> max 5

<interactive>:75:1: error:
    • No instance for (Show (Integer -> Integer))
        arising from a use of ‘print’
        (maybe you haven't applied a function to enough arguments?)
    • In a stmt of an interactive GHCi command: print it
----------------------------------------------  ^^^^^ ^^

GHCi is always implicitly running the print function to display expressions and values on the screen; print takes an argument, and for GHCi, that argument is often it. But it’s not only GHCi that can pass it as an argument to functions – you can, too!

λ> sum [1..500]
125250

λ> it / 15
8350.0

λ> it * 2
16700.0

Join Type Classes for courses and projects to get you started and make you an expert in FP with Haskell.