news

[Published in Open Source For You (OSFY) magazine, August 2013 edition.]

Emacs is a popular text editor that can be extended and customized. Haskell is a statically typed, functional programming language. Haskell-mode is a Emacs major mode that provides support to write and use Haskell programs. This article explains interesting features and tips on using Haskell-mode with GNU Emacs.

You can install Haskell-mode using your distribution package manager. For example, on Fedora you can use:

$ sudo yum install emacs-haskell-mode

Mode

You can enter Haskell-mode when opening a Haskell source file that has an extension .hs, or it can be started within Emacs using:

M-x haskell-mode

On the modeline, you will now see “(Haskell)”, indicating that the Haskell mode has been activated. You can enter the indent mode using:

M-x haskell-indent-mode

The modeline will now show “(Haskell Ind)”.

Interpreter

To load a Haskell source file into the interpreter, use C-c C-l. It will create a new buffer, load the module in the current buffer and give a prompt to work with. Consider the following Square.hs program:

square :: Int -> int
square x = x * x

Opening a Square.hs file in an Emacs buffer, and running C-c C-l will produce the following in a new buffer:

GHCi, version 7.0.4: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Prelude> :load "/home/guest/Square.hs"
[1 of 1] Compiling Main             ( /home/guest/Square.hs, interpreted )
Ok, modules loaded: Main.
*Main> 

If you have multiple buffers opened within Emacs, you can directly switch from the (Haskell) mode buffer to the Haskell interpreter using C-c C-z.

Insertions

The equal to (=) sign can be inserted, and the function type can be neatly aligned with the C-c C-= key stroke. If you type the following function:

volume :: Int -> Int -> Int
volume x

… and keep the cursor after ‘x’ and type C-c C-=, the equal to sign is inserted, and the code gets neatly aligned:

volume   :: Int -> Int -> Int
volume x = 

In the following code snippet, after ‘y’, if you hit Return followed by C-c C-|, a guard symbol is inserted:

max :: (Ord a) => a -> a -> a
max x y
 |

After inserting the second guard in the above example, the ‘otherwise’ keyword can be inserted and the code is aligned using C-c C-o:

max :: (Ord a) => a -> a -> a
max x y
 | x > y     = x
 | otherwise = 

The ‘where’ clause is produced using C-c C-w. In the following example, pressing return after ‘r’, and using C-c C-w inserts the ‘where’ clause:

circleArea :: Float -> Float
circleArea r = pi * r * r
    where 

You can insert the type annotation for a function using C-u C-c C-t. Consider the sphereVolume function:

sphereVolume r = 4 / 3 * pi * r * r * r
    where pi = 3.1412

Placing the cursor on ‘sphereVolume’ and typing C-u C-c C-t produces the following:

sphereVolume :: Fractional a => a -> a
sphereVolume r = 4 / 3 * pi * r * r * r
    where pi = 3.1412

Formatting

There are a number of shortcut commands that are useful for indentation. Let’s suppose you have the following function with the cursor position indicated by ‘_’:

greeting :: String -> String
greeting x = "Hello" ++ x ++
_

Hitting TAB will take you through the different possible positions for inserting code. When you press TAB for the first time, the cursor will move under ‘Hello’; if you wish to complete the string concatenation (++), issue the following code:

greeting :: String -> String
greeting x = "Hello" ++ x ++
       	     _

Hitting TAB again prepends ‘greeting’ and the cursor will be placed under ‘x’ for you to add another test condition, as follows:

greeting :: String -> String
greeting x = "Hello" ++ x ++
greeting _

Hitting TAB again will move the cursor to the first column if you want to add any text:

greeting :: String -> String
greeting x = "Hello" ++ x ++
_

As you keep hitting TAB again and again, the above sequence will repeat. Comments in Haskell begin with ’- -’.

one -- 1
two -- 2
three -- 3
four -- 4
five -- 5
six -- 6
seven -- 7

After marking the above region, use M-x align-regexp followed by ’–’ for the regexp, and the comments will be aligned:

one    -- 1
two    -- 2
three  -- 3
four   -- 4
five   -- 5
six    -- 6
seven  -- 7

C-c C-. helps align the code neatly. Consider the Area.hs program:

area :: Int -> Int -> Int
area breadth height = breadth * height

After marking the above program, and using C-c C-., the code becomes:

area                :: Int -> Int -> Int
area breadth height = breadth * height

Query

To know the Haskell-mode version, use M-x haskell-version. As an example:

  Using haskell-mode version v2.8.0

C-c C-i on a symbol will prompt for getting information about the symbol. For example, ‘Show info of (default Int):’ lists the following:

data Int = GHC.Types.I# GHC.Prim.Int# 	-- Defined in GHC.Types
instance Bounded Int -- Defined in GHC.Enum
instance Enum Int -- Defined in GHC.Enum
instance Eq Int -- Defined in GHC.Base
instance Integral Int -- Defined in GHC.Real
instance Num Int -- Defined in GHC.Num
instance Ord Int -- Defined in GHC.Base
instance Read Int -- Defined in GHC.Read
instance Real Int -- Defined in GHC.Real
instance Show Int -- Defined in GHC.Show

C-c C-t will obtain the type of the symbol with the prompt ‘Show type of (default pi):’. For example:

pi :: Floating a => a

C-c TAB on a symbol returns its definition at the interpreter prompt, as follows:

*Main> :info sphereVolume
sphereVolume :: Fractional a => a -> a
  	-- Defined at /home/guest/Sphere.hs:1:1-12

To find haddock information for a symbol, you can use C-c C-d. Searching for ‘Float’, for example, opens up file:///usr/share/doc/ghc/html/libraries/ghc-prim-0.2.0.0/GHC-Types.html on Fedora.

To use the Hayoo search engine, you can use M-x haskell-hayoo. It will prompt with:

  Hayoo query:

The query responses are shown in a browser. Similarily, the Hoogle engine can be queried using M-x haskell-hoogle. If you searched for ‘show’, it will open the URL http://www.haskell.org/hoogle/?q=show with the search results.

Files ending with .lhs are literate Haskell programs. You can use Richard Bird style to separate text and code as follows:

Insert blank line before the code
 
> quicksort :: Ord a => [a] -> [a]
> quicksort []     = []
> quicksort (p:xs) = (quicksort lesser) ++ [p] ++ (quicksort greater)
>    where
>        lesser  = filter (< p) xs
>        greater = filter (>= p) xs

Insert blank line after the code

The modeline will indicate that you are in the ‘(LitHaskell/bird)’ minor mode.

The hasktag package needs to be installed to help generate TAGS file for source files. For example:

$ hasktags Test.hs

It will create both tags and TAGS files. You can use M-. in the Haskell buffer to search for a tag.

Checks

HLint is a tool that provides suggestions to improve Haskell programs. C-c C-v helps to run hlint on a buffer. Make sure you have the tool installed on your system before using it. For example, running C-c C-v on the above literate quicksort Haskell program suggests:

-*- mode: compilation; default-directory: "~/" -*-
Compilation started at Thu Jun  6 21:31:54

hlint QuickSort.lhs
QuickSort.lhs:6:22: Warning: Redundant bracket
Found:
  (quicksort lesser) ++ [p] ++ (quicksort greater)
Why not:
  quicksort lesser ++ [p] ++ (quicksort greater)

QuickSort.lhs:6:44: Warning: Redundant bracket
Found:
  [p] ++ (quicksort greater)
Why not:
  [p] ++ quicksort greater

2 suggestions

Compilation exited abnormally with code 1 at Thu Jun  6 21:31:54