Flymake-mode for Haskell (Emacs)

追記
perlスクリプトが不要な以下の方法がおすすめです。
Flymake-mode for Haskell (Emacs) without perl script - 落書き、時々落学


flymake-mode はエラーがあるとそれを知らせていくれる.
haskellで使うには少し設定が必要.

環境

下準備

/usr/local/binなどパスがとおったところにperlスクリプトをおく

#!/usr/bin/env perl
# flycheck_haskell.pl

### Please rewrite the following 3 variables
### ($ghc, @ghc_options and @ghc_packages)

$ghc = '/usr/bin/ghc'; # where is ghc
@ghc_options  = ();   # e.g. ('-fglasgow-exts')
@ghc_packages = ();          # e.g. ('QuickCheck')

### the following should not been edited ###

use File::Temp qw /tempfile tempdir/;
File::Temp->safe_level( File::Temp::HIGH );

($source, $base_dir) = @ARGV;

$source =~ s/ /\\ /g;
$base_dir =~ s/ /\\ /g;

@command = ($ghc,
            '--make',
            '-fbyte-code',
            "-i$base_dir",
            "-i$base_dir/..",
	    "-i$base_dir/../..",
	    "-i$base_dir/../../..",
	    "-i$base_dir/../../../..",
	    "-i$base_dir/../../../../..",
            $source);

while(@ghc_options) {
    push(@command, shift @ghc_options);
}

while(@ghc_packages) {
    push(@command, '-package');
    push(@command, shift @ghc_packages);
}

$dir = tempdir( CLEANUP => 1 );
($fh, $filename) = tempfile( DIR => $dir );

system("@command >$filename 2>&1");
open(MESSAGE, $filename);
while(<MESSAGE>) {
    if(/(^\S+\.hs|\.lhs)(:\d*:\d*:)\s?(.*)/) {
        print "\n";
        print $1;
        print $2;
        $rest = $3;
	chomp $rest;
	print $rest;
	next;
    }
    if(/\s+(.*)/) {
	$rest = $1;
        chomp $rest;
	print $rest;
        print " ";
	next;
    }
}
close($fh);
print "\n";

.emacs の編集

;======================================================================
; flymake-mode for haskell
;======================================================================
(require 'flymake)
(defun flymake-Haskell-init ()
  (flymake-simple-make-init-impl
   'flymake-create-temp-with-folder-structure nil nil
   (file-name-nondirectory buffer-file-name)
   'flymake-get-Haskell-cmdline))

(defun flymake-get-Haskell-cmdline (source base-dir)
  (list "flycheck_haskell.pl"
	(list source base-dir)))

(push '(".+\\.hs$" flymake-Haskell-init flymake-simple-java-cleanup)
      flymake-allowed-file-name-masks)
(push '(".+\\.lhs$" flymake-Haskell-init flymake-simple-java-cleanup)
      flymake-allowed-file-name-masks)
(push
 '("^\\(\.+\.hs\\|\.lhs\\):\\([0-9]+\\):\\([0-9]+\\):\\(.+\\)"
   1 2 3 4) flymake-err-line-patterns)

(add-hook 'haskell-mode-hook
	  '(lambda ()
	     (if (not (null buffer-file-name)) (flymake-mode))))

;; Display messages at the minibuffer
(global-set-key "\C-cd"
                'flymake-show-and-sit )
(defun flymake-show-and-sit ()
  "Displays the error/warning for the current line in the minibuffer"
  (interactive)
  (progn
    (let* ( (line-no             (flymake-current-line-no) )
	    (line-err-info-list  (nth 0 (flymake-find-err-info flymake-err-info line-no)))
	    (count               (length line-err-info-list))
	    )
      (while (> count 0)
	(when line-err-info-list
	  (let* ((file       (flymake-ler-file (nth (1- count) line-err-info-list)))
		 (full-file  (flymake-ler-full-file (nth (1- count) line-err-info-list)))
		 (text (flymake-ler-text (nth (1- count) line-err-info-list)))
		 (line       (flymake-ler-line (nth (1- count) line-err-info-list))))
	    (message "[%s] %s" line text)
	    )
	  )
	(setq count (1- count)))))
  (sit-for 60.0)
  )
;;

実際に使ってみた

こんなかんじ.