Difference between revisions of "Haskell mode for Emacs"

From HaskellWiki
Jump to: navigation, search
(Fix bug in elisp code)
(Redirect to Emacs which will be part of a series of pages.)
(29 intermediate revisions by 7 users not shown)
Line 1: Line 1:
haskell-mode is a major mode for Emacs and XEmacs specifically for writing Haskell code. You can get haskell-mode from the web page: http://projects.haskell.org/haskellmode-emacs/ or on Debian you can type <code>apt-get install haskell-mode</code> (although this currently doesn't have the latest version). It is currently maintained by Svein Ove Aas[http://www.mail-archive.com/haskell-cafe@haskell.org/msg66300.html].
==Development Version==
See also [http://trac.haskell.org/haskellmode-emacs/report/1 Active Tickets] in bug tracker.
Download and unpack the basic mode and modules into a suitable directory, e.g. <code>~/lib/emacs/haskell-mode/</code> where <code>~</code> stands for your home directory.
Assuming you have placed the basic mode haskell-mode.el and the modules you want to use in the directory <code>~/lib/emacs/haskell-mode/</code>, add the following command to your init file (<code>~/.emacs</code>):
==== Inferior Mode ====
Normally, inf-haskell automatically finds ghci or hugs in your <code>PATH</code>, but if that's not the case (common under Windows), or if you need to specify your preference, just tell Emacs which executable to use with:
you can test the value of `system-type':
(setq haskell-program-name
(if (eq system-type 'cygwin)
Note that Cygwin binaries tend to interact poorly with NTEmacs, especially
w.r.t signal-handling.
==Tips and use==
Handy keybindings in haskell-mode. See the documentation <code>C-h m</code> for more information:
*<code>C-c C-=</code> inserts an = sign and lines up type signatures and other pattern matches nicely.
*<code>C-c C-|</code> inserts a guard
*<code>C-c C-o</code> inserts a guard <hask>| otherwise =</hask> and lines up existing guards
*<code>C-c C-w</code> inserts a where keyword
*<code>C-c C-.</code> aligns code over a region in a "sensible" fashion.
Now in version 2.2:
*<code>C-c C-t</code> gets :type for symbol at point, and remembers it
*<code>C-u C-c C-t</code> inserts a type annotation, for symbol at point, on the line above
*<code>C-c C-i</code> gets :info for symbol at point
*<code>C-c M-.</code> find definition of (interpreted) symbol at point
(See the section below on [[#inf-haskell.el:_the_best_thing_since_the_breadknife|inf-haskell]].)
Here's an example for <code>C-c C-=</code>. Put your cursor after myInt and hit <code>C-c C-=</code>
blah :: Int -> Int
blah myInt
blah :: Int -> Int
blah myInt =
You could also achieve the same effect by selecting the region and typing <code>C-c C-.</code>
You can also use Haskell-Mode to load Emacs buffers with Haskell code in either Hugs or GHC. To load something in Hugs or ghci, type <code>C-c C-l</code> to load the file. Then, you can go on to type <code>C-c C-r</code> (or simply <code>C-c C-l</code> again) to reload the current module when you have made a change.
=== Indentation ===
Indentation is one thing that nearly all programming modes provide. However, indenting Haskell code is very hard: for a given line, there are nearly always more than column for which indentation makes sense. For example, imagine the following is open in a haskell-mode buffer, where <code>!</code> represents the point:
foo :: Int -> String
foo 0 = f 4 ++ s
where f 4 = "hello" ++
You want to finish off the expression you were writing in the last line. Haskell-mode indents to be underneath the <code>"</code> character at the beginning of <code>"hello"</code>:
where f 4 = "hello" ++
where f 4 = "hello" ++
You want to add a second equation for <code>f</code>. Haskell-mode will indent to line up with the first argument, and fill in the <code>f</code> in the equation:
where f 4 = "hello" ++
f !
This is an unlikely choice as the expression in the previous line isn't complete, but haskell-mode isn't smart enough to know that. (If <code>f</code> had been something without arguments, like <hask>where f = "hello"</hask>, then it's impossible to have more than one equation and haskell-mode won't offer this indentation level.)
You want to add a second binding to the <code>where</code>-block. Haskell-mode indents to line up with the <code>f</code>:
where f 4 = "hello" ++
<li>You want to start an entirely new top-level binding. Haskell-mode indents to the first column:
foo :: Int -> String
foo 0 = f 4 ++ s
where f 4 = "hello" ++
These four locations can be reached by repeatedly pressing <code>TAB</code>. This is what's known as the tab-cycle. The innermost location is offered first, then cycling progresses outwards. Although this may seem like an inefficient system (and it is indeed a shame that Haskell's design didn't result in an unambiguous indentation system), you do quickly get used to the tab-cycle and indenting Haskell code.
==== indent-region ====
==== Unicodifying symbols (Pretty Lambda for Haskell-mode) ====
In Haskell code, you can end up using a lot of mathematical symbols. It is possible to hack the fontifying features of Emacs to change the ASCII textual representations of arrows and operators into the nice-looking real symbols, much like you could with TeX. The following code is a compilation of Emacs lisp code found on the Emacs wiki on the [http://www.emacswiki.org/cgi-bin/wiki/PrettyLambda#toc4 Pretty Lambda] page (that page also has examples of how to apply the general Unicode defuns to other languages):
Haskell-mode has included this feature for a long time now, so you probably just need to <code>(setq haskell-font-lock-symbols t)</code> in your .emacs to use this feature.
(defun unicode-symbol (name)
or GREATER-THAN into an actual Unicode character code. "
(decode-char 'ucs (case name
(left-arrow 8592)
(up-arrow 8593)
(right-arrow 8594)
(down-arrow 8595)
(double-vertical-bar #X2551)
(equal #X003d)
(not-equal #X2260)
(identical #X2261)
(not-identical #X2262)
(less-than #X003c)
(greater-than #X003e)
(logical-and #X2227)
(logical-or #X2228)
(logical-neg #X00AC)
('nil #X2205)
(horizontal-ellipsis #X2026)
(double-exclamation #X203C)
(prime #X2032)
(double-prime #X2033)
(for-all #X2200)
(there-exists #X2203)
(element-of #X2208)
(square-root #X221A)
(squared #X00B2)
(cubed #X00B3)
(lambda #X03BB)
(alpha #X03B1)
(beta #X03B2)
(gamma #X03B3)
(delta #X03B4))))
Unicode symbol SYMBOL looked up with UNICODE-SYMBOL."
nil `((,pattern
,(unicode-symbol symbol)
(defun substitute-patterns-with-unicode (patterns)
(mapcar #'(lambda (x)
(substitute-pattern-with-unicode (car x)
(cdr x)))
(defun haskell-unicode ()
(cons "\\(<nowiki>''</nowiki>\\)" 'double-prime)
(add-hook 'haskell-mode-hook 'haskell-unicode)</code>
== Bugs ==
Bugs and feature requests should be sent to the maintainer [mailto:svein.ove@aas.no Svein Ove Aas].
For people using the Debian package, Debian maintains a [http://bugs.debian.org/cgi-bin/pkgreport.cgi?pkg=haskell-mode list of bugs] for haskell-mode, they should be reported there.
To fix this, find where the haskell mode package is installed on your system. (Usually <code>/usr/share/emacs/site-lisp/haskell-mode</code>). Edit the file <code>haskell-indent.el</code> and add the lines:
(unless (fboundp 'line-end-position)
(defun line-end-position (&optional n)
(end-of-line n)
This one shows up when typing in code (at various spots - most often when typing a qualified function, such as <hask>List.map</hask>.)
To fix this one, edit the file <code>haskell-font-lock.el</code>. Look for the line that says:
(defvar haskell-default-face nil)
and change this to
(defvar haskell-default-face 'default)
In my version, this is line 168.
Then, look for the line that says:
(,qvarid 0 haskell-default-face)
and change it to
For me, this is line 326 of the file.
YMMV - hope this helps.
=== GNU Emacs ===
==== ghci buffer infested with "^J"s, C-c C-t doesn't work ====
(only happens after loading a haskell file into ghci)
== inf-haskell.el: the best thing since the breadknife ==
inf-haskell.el is _awesome_. At one point I decided to sit down and write a list of functions I'd love to have in haskell-mode, intending to write them myself. I thought I'd check to see whether the key shortcuts I'd chosen were free but I was surprised to find that ''every one'' of these functions is already provided by inf-haskell.el! Here's a selection of the highlights:
=== Getting set up ===
(require 'inf-haskell)
=== inferior-haskell-type (C-c C-t) ===
Say you have the following code:
Perhaps you've forgotten the order of arguments to foldr. It's easily done; I can never remember whether the operation or final value comes first. That's easy to check: just put your point between the 'f' and 'r' of 'foldr' and hit C-c C-t RET. The type of foldr will be revealed in the echo area. This isn't particularly impressive; haskell-doc.el already did this. However, this will work for ''any'' function in the module in question ''or'' in those modules imported by the current module (including the standard libs)!
-!-map _ [] = []
map f (x:xs) = f x : map f xs
-!-map _ [] = []
map f (x:xs) = f x : map f xs
=== inferior-haskell-info (C-c C-i) ===
* The definition of an algebraic datatype given its name. E.g. try <code>:info Bool</code>. The output will contain something like <code>data Bool = True | False</code>.
* The classes a type instantiates given the type's name. <code>:info Bool</code> will also give you the classes Bool instantiates. If you can't see an instance you think should be there, make sure the module where that instance is declared is loaded.
* The type of a function, given its name.
* The expansion of a type synonym given that synonym's name.
=== inferior-haskell-find-definition (C-c M-.) ===
(Basically, it only works on interpreted code, for which ghci has location information. If you want a more general find-definition, use hasktags to create a TAGS file and then use the normal emacs <code>M-.</code> with that. -- mrd)
: Note that you can also create a TAGS file using GHCi's :etags command. [[User:DavidHouse|DavidHouse]] 14:38, 29 April 2007 (UTC)
: Again, :etags/:ctags only works for interpreted code.
: <code>inferior-haskell-mode</code> is missing TAB completion, which in GHCi works basically for everything (GHCi commands, modules, functions, language extensions, file names etc.). -- Oleksandr Manzyuk
== Tricks and tweaks ==
=== Automatic unit testing ===
Here's a cute trick I've evolved:
I'm a great fan of [[unit test first]], as described by eXtremeProgramming on TheOriginalWiki.
This elisp code will run the <code>compile</code> command from the F12 key in emacs. The output will popup a new window twelve lines tall. If the compilation is successful (exitcode zero) the window goes away. If the exitcode is 1 or greater, the window stays so you can see the output.
(require 'compile)
;; this means hitting the compile button always saves the buffer
;; having to separately hit C-x C-s is a waste of time
;; make the compile window stick at 12 lines tall
(setq compilation-window-height 12)
;; from enberg on #emacs
;; if the compilation has a zero exit code,
;; the windows disappears after two seconds
;; otherwise it stays
(setq compilation-finish-function
(lambda (buf str)
(unless (string-match "exited abnormally" str)
"2 sec" nil 'delete-windows-on
(message "No Compilation Errors!"))))
;; one-button testing, tada!
(global-set-key [f12] 'compile)
import HUnit
import System
myTestList =
TestList [
h = runTestTT myTestList
main = do c <- h
putStr $ show c
let errs = errors c
fails = failures c
System.exitWith (codeGet errs fails)
codeGet errs fails
| fails > 0 = ExitFailure 2
| errs > 0 = ExitFailure 1
| otherwise = ExitSuccess
-- Local Variables:
-- End:
=== Hoogle integration ===
=== Using rectangular region commands ===
<code>C-x r o</code> is "Open Rectangle". It will shift any text within the rectangle to the right side. Also see:
<code>C-x r t</code> is "String Rectangle". It will shift any text within the rectangle over to the right, and insert a given string prefixing all the lines in the region. If comment-region didn't already exist, you could use this instead, for example.
<code>C-x r d</code> is "Delete Rectangle". It will delete the contents of the rectangle and move anything on the right over.
<code>C-x r r</code> is "Copy Rectangle to Register". It will prompt you for a register number so it can save it for later.
<code>C-x r g</code> is "Insert register". This will insert the contents of the given register, overwriting whatever happens to be within the target rectangle. (So make room)
<code>C-x r k</code> is "Kill rectangle". Delete rectangle and save contents for:
<code>C-x r y</code> is "Yank rectangle". This will insert the contents of
the last killed rectangle.
As with all Emacs modifier combos, you can type <code>C-x r C-h</code> to find out what keys are bound beginning with the <code>C-x r</code> prefix.
=== Aligning code ===
For example, I often line up my Haddock comments:
f :: a -- ^ does a
-> Foo b -- ^ and b
-> c -- ^ to c
Select the region, and let the regexp be: <code>--</code>
f :: a -- ^ does a
-> Foo b -- ^ and b
-> c -- ^ to c
Of course, this works for just about anything. Personally, I've globally bound it to <code>C-x a r</code>:
<code>(global-set-key (kbd "C-x a r") 'align-regexp)</code>.
=== Automatically building ===
Emacs 21 has a package that can be installed (included by default in 22 and up) called 'FlyMake'; the idea is that as you are editing away, it occasionally calls the interpreter/compiler automatically and keeps track of whether the code works or not. You can fairly easily get it to work for Haskell as well; see [http://www.emacswiki.org/cgi-bin/wiki/FlymakeHaskell FlymakeHaskell] on the Emacs wiki.
=== Emacs Integration with Hayoo ===
(lambda ()
Added 22-12-2008 - Promt for hayoo word
(defun rgr/hayoo()
Alternatively use the excellent browse-apropos-url stuff:
[http://richardriley.net Richard]
[[User:Tbh|Tbh]] 00:56, 25 January 2009 (UTC)
=== Integration with HLint ===
[http://www-users.cs.york.ac.uk/~ndm/hlint/ HLint] could be used directly from Emacs buffer. There is [http://www.cs.york.ac.uk/fp/darcs/hlint/data/hs-lint.el hs-lint.el] package (in HLint distribution, in the data subdirectory), that allows user to run HLint and navigate through errors, or apply suggestions to the source code.
(defun my-haskell-mode-hook ()
[[Category:Development tools]]
=== Folding ===
For folding parts of code you can use
*and '''hs-outline-level''' (based on py-outline-level created by Gb)
(defun hsk-outline-level ()
(let (buffer-invisibility-spec)
(skip-chars-forward "\t ")
;; this get called after haskell mode is enabled
(lambda ()
;; enable our level computation
(setq outline-level 'hsk-outline-level)
;; turn on outline mode
(outline-minor-mode t)
;; initially hide all but the headers
*Also, you can use '''toggle-selective-display''' for global folding
;; folding for all rows, starting on the current column
(defun toggle-selective-display (column)
(interactive "P")
(or column
(unless selective-display
(defun toggle-hiding (column)
(interactive "P")
(if hs-minor-mode
(if (condition-case nil
(error t))
(toggle-selective-display column)))
*and '''narrowing capabilities''' for folding the rest of code
(put 'narrow-to-defun 'disabled nil)
(put 'narrow-to-page 'disabled nil)
(put 'narrow-to-region 'disabled nil)
*or '''folding-mode''', if you do not mind add markers such as '''{-{{{-}''' and '''{-}}}-}''' in code.
=== Speedbar ===
Emacs has a [http://www.emacswiki.org/emacs/SpeedBar SpeedBar] which works quite nice together with haskell-mode and also detects syntactic elements such as variables, imports, instances, classes.
Just add
(require 'speedbar)
to your .emacs file and fire up speedbar with <code>M-x speedbar</code>.
=== Literate Haskell ===
M-x customize-variable RET haskell-literate-default

Latest revision as of 10:01, 18 May 2012

Redirect to: