Flycheck + Stack

Wut?

Stack is a relatively new tool setting out to fix common problems in the current Haskell tool-chain, the most common one know as cabal hell. It is really a big improvement of everything I have tried so far, as it completely isolates your build/dev environment and lets you focus on developing instead of manually wrestling with broken dependency graphs.

Emacs integration

While there is [tooling][ide-backend] in the making that will likely outperform the combination of flycheck and [company-mode]company, it is available now and works reasonably well.

To integrate stack with flycheck I tried to set the ghc command for the haskell-ghc checker, but couldn’t get that to work. The next thing I tried was looking at the source. I copied and pasted the checker definition for haskell-ghc, amended and called it haskell-stack:

(flycheck-define-checker haskell-stack
  "A Haskell syntax and type checker using ghc.

See URL `http://www.haskell.org/ghc/'."
  :command ("stack" "ghc" "--" "-Wall" "-fno-code"
            (option-flag "-no-user-package-db"
                         flycheck-ghc-no-user-package-database)
            (option-list "-package-db" flycheck-ghc-package-databases)
            (option-list "-i" flycheck-ghc-search-path concat)
            ;; Include the parent directory of the current module tree, to
            ;; properly resolve local imports
            (eval (concat
                   "-i"
                   (flycheck-module-root-directory
                    (flycheck-find-in-buffer flycheck-haskell-module-re))))
            (option-list "-X" flycheck-ghc-language-extensions concat)
            (eval flycheck-ghc-args)
            "-x" (eval
                  (pcase major-mode
                    (`haskell-mode "hs")
                    (`literate-haskell-mode "lhs")))
            source)
  :error-patterns
  ((warning line-start (file-name) ":" line ":" column ":"
            (or " " "\n    ") "Warning:" (optional "\n")
            (message
             (one-or-more " ") (one-or-more not-newline)
             (zero-or-more "\n"
                           (one-or-more " ")
                           (one-or-more not-newline)))
            line-end)
   (error line-start (file-name) ":" line ":" column ":"
          (or (message (one-or-more not-newline))
              (and "\n"
                   (message
                    (one-or-more " ") (one-or-more not-newline)
                    (zero-or-more "\n"
                                  (one-or-more " ")
                                  (one-or-more not-newline)))))
          line-end))
  :error-filter
  (lambda (errors)
    (flycheck-sanitize-errors (flycheck-dedent-error-messages errors)))
  :modes (haskell-mode literate-haskell-mode)
  :next-checkers ((warning . haskell-hlint)))

I had to disable the haskell-ghc check by putting it into the flycheck-disabled-checkers list, and add the last bit to my Haskell initialization function:

(defun haskell-mode-setup-hook ()
  (interactive)
  (progn
    (turn-on-haskell-indent) ; haskell stuff
    (turn-on-haskell-doc)
    (turn-on-haskell-decl-scan)
    (interactive-haskell-mode)
    (flycheck-select-checker 'haskell-stack)))

Company mode can also be made to integrate with ghc like this to complete modules symbols while coding.

Hope it helps!