Emacs 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/