Getting Started with Haskell on Emacs

0
6549

EmacsEmacs is a popular text editor that can be extended and customised. Haskell is a statically typed, functional programming language. Haskell-mode is an 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 yet 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 the following file: ///usr/share/doc/ghc/html/libraries/ghcprim-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. Similarly, 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 the 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

References

[1]    Haskell. http://www.haskell.org/haskellwiki/Haskell
[2]    GNU Emacs. http://www.gnu.org/software/emacs/
[3]    Haskell mode 2.8. http://projects.haskell.org/haskellmode-emacs
[4]    Hasktag. http://hackage.haskell.org/package/hasktags
[5]    HLint. http://community.haskell.org/~ndm/hlint/

LEAVE A REPLY

Please enter your comment!
Please enter your name here