Hi, Purescript! - Emacs for Purescript Development

Purescript is a language that borrows many ideas from Haskell, but compiles down to Javascript. In sum, Purescript gives you:

Here’s a sample:

module Main where

import Debug.Trace

data RPS = R | P | S

-- defining equality for the RPS data type
instance eqRPS :: Eq RPS where
  (==) R R = true
  (==) P P = true
  (==) S S = true
  (==) _ _ = false
  (/=) l r = not (l == r)

factorial :: Number -> Number
factorial 0 = 1
factorial n = n * factorial (n - 1)

-- iterative application of a function f
iterate :: forall a. (a -> a) -> Number -> a -> a
iterate _ 0 x = x
iterate f n x = iterate f (n - 1) (f x)

main = trace $ show $ iterate (\x -> x+1) 10 1

I highly recommend Phil Freeman’s freely available purescript book, as well as the docs for more details on the language itself.

Before I dive into the details of my purescript + emacs setup, I’d like to share some background.

Learning to Ask A Lot of My Editor

I’ve worked with emacs for a long time. Part of my evaluating a new (to me) programming language is determining how much emacs can do for me.

I’ve been a Haskeller for just over a year now. When I realized how much of the effort of programming Haskell I could push into emacs, I was blown away.

Thanks to ghc-mod, I’m able to (without leaving my emacs buffer):

I cannot over-emphasize how powerful this setup is. Every time I save, it is as if a unit test suite has been run over my entire project, only, even more powerful than that thanks to Curry-Howard. Not only that, but I don’t have to interrupt my editing flow to do so.

Here’s a few screenshots of this in action:

Type Details at Point

Information at Point

Type Check on Save

Display Error at Point

Display Warning at Point

More Information on Emacs + Haskell

I only use a subset of the full power of emacs for Haskell development, and already I reap enormous benefits. For setting up emacs and Haskell, I recommend Alejandro Serrano’s post.

Purescript and Emacs

I’ve arrived at Purescript and I’m ready to develop! In order to get the most of my editor, I went looking around for tools to help emacs understand purescript. Here’s what I found:

Follow the instructions for installing each of the above. Note that installing purscheck requires a working Haskell installation.

Here’s the relevant bits of my init.el with comments in-line:

;; flycheck - automated checker module for emacs
;; import the flycheck symbols
(require 'flycheck)

;; connect purscheck to emacs, parsing errors and warnings
(flycheck-define-checker purs-check
                         "Use purscheck to flycheck PureScript code."
                         :command ("purscheck" source source-original temporary-file-name)
                         :error-patterns
                         ((error line-start
                                 (or (and "Error at " (file-name) " line " line ", column " column ":" (zero-or-more " "))
                                     (and "\"" (file-name) "\" (line " line ", column " column "):"))
                                 (or (message (one-or-more not-newline))
                                     (and "\n"
                                          (message
                                           (zero-or-more " ") (one-or-more not-newline)
                                           (zero-or-more "\n"
                                                         (zero-or-more " ")
                                                         (one-or-more not-newline)))))
                                 line-end))
                         :modes purescript-mode)

;; connect flycheck with purscheck
(add-to-list 'flycheck-checkers 'purs-check)

;; add the purescript-mode directory to emacs necessary because
;; purescript isn't on melpa/marmalde at the moment
(add-to-list 'load-path "~/development/purescript-mode/")

;; enable purescript smart indentation and purscheck whenever a
;; purescript file is loaded into emacs
(require 'purescript-mode-autoloads)
(add-hook 'purescript-mode-hook 'turn-on-purescript-indentation)
(add-hook 'purescript-mode-hook 'flycheck-mode)

With the setup above, I get:

What’s Missing?

I’m missing the following in purescript:

I’ve yet to work with elisp, but I suspect one of the quickest paths to get these kinds of features is to start-up purescript interpret mode (psci) in the background, and have emacs communicate with it to parse out the results of :k (expression kind), :i (expression information), and :t (expression type).

All in all, though, I’m very pleased with the purescript editing ecosystem. It’s enough to go far as it is.