Wednesday, April 18, 2007

Getting to know erlang-mode

The very first errata listed for the beta Programming Erlang: Software for a Concurrent World is that Joe should include a chapter on erlang programming tools, and it specifically mentions erlang-mode for emacs. Being an emacs user, this piqued my interest and I went off in search of it. Here's a quick run-down of what I found.

Installing and Running erlang-mode

erlang-mode is part of the OTP erlang distribution, although it's kind of hidden. Since I compiled and installed my distribution in the /usr tree, All my examples will point there. Even though the needed elisp files are installed and easy to get runing, you'll need to download and install the erlang man pages. I put them in /usr/lib/erlang on my system.

Once the code and documentation is installed, you can set it up by adding the following elisp code to your .emacs file:

;; setup erlang mode
;; add the location of the elisp files to the load-path
(setq load-path (cons "/usr/lib/erlang/lib/tools-2.5.3/emacs"
;; set the location of the man page hierarchy
(setq erlang-root-dir "/usr/lib/erlang")
;; add the home of the erlang binaries to the exec-path
(setq exec-path (cons "/usr/lib/bin" exec-path))
;; load and eval the erlang-start package to set up
;; everything else
(require 'erlang-start)

(Feel free to strip out the comments, They aren't in my .emacs file either.)

First Impressions

The first thing that I found to like about erlang-mode was the ability to run an erlang shell inside emacs. Since I like to play in a REPL while I program, having a shell running inside my editor is great. While I normally have my emacs running much larger than this, I wanted to show a full-sized screenshot so you could read the text. Working this way just rocks!

Picture of an emacs session with the erl shell and syntax highlighting

The screenshot above also shows off erlang-mode's syntax highlighting. There are four levels of syntax highlighting ranging from off to 'Christmas Tree Mode' (which is the highlighting level I run in).

Another thing that leaped out at me, was the auto-formatter/indenter that's built into erlang-mode. It was a little bit strange to be typing along and hit an arrow (->) only to have emacs automagically move to the next line and indent for me. I got used to it in a couple of minutes, and realized that I could get to like it — if I felt like it was using good style, it doesn't match up against the example in Programming Erlang: Software for a Concurrent World. Anyone want to weigh in on how good or bad it looks?

qsort([]) ->
qsort([Pivot|T]) ->
qsort([X || X <- T,
X < Pivot])
++ [Pivot] ++
qsort([X || X <- T,
X >= Pivot]).

(By the way, it also automatically creates an indented, new line in a lot of cases. I'm not quite sure what all of them are yet.)

Since I'm on the topic of code formatting, I thought I'd toss out several small but interesting functions.

  • erlang-align-arrows (C-c C-a): I think that well used whitespace can make reading a program easier, and aligning similar parts of a program is one example. Running erlang-align-arrows against this region:

    for(Max, Max, F) -> [F(Max)];
    for(I, Max, F) -> [F(I)| for(I+1, Max, F)].

    sum([H|T]) -> H + sum(T);
    sum([]) -> 0.

    map(_, []) -> [];
    map(F, [H|T])-> [F(H) | map(F, T)].

    will reformat it to look like this:

    for(Max, Max, F) -> [F(Max)];
    for(I, Max, F) -> [F(I)| for(I+1, Max, F)].

    sum([H|T]) -> H + sum(T);
    sum([]) -> 0.

    map(_, []) -> [];
    map(F, [H|T]) -> [F(H) | map(F, T)].

  • erlang-generate-new-clause (C-c C-j): This command (and the next one) will likely save some typing. It generates a new clause in the curent function, immediately below the current clause, and puts the point at the argument list inside the parens. For example, running erlang-generate-new-clause with the point on the rectangle clause of the following function:

    area({rectangle, Width, Ht}) -> Width * Ht;
    area({circle, R}) -> 3.14159 * R * R;
    area({square,X}) -> geometry:area({rectangle, X, X}).

    will create:

    area({rectangle, Width, Ht}) -> Width * Ht;
    area() ->
    area({circle, R}) -> 3.14159 * R * R;
    area({square,X}) -> geometry:area({rectangle, X, X}).

    One small gotcha is that there's no closing punctuation for the generated clause, so you'll need to type your own semicolon or period.

  • erlang-clone-arguments (C-c C-y): This command will insert the arguments from the previous clause at the current point. If you run it immediately after the erlang-generate-new-clause command above, you'll the new clause will be changed to read:

    area({rectangle, Width, Ht}) ->

    which would be easy to edit to create a triangle clause.

One set of commands I didn't play with were the compilation commands. Once I get to that section of Programming Erlang: Software for a Concurrent World, I'm sure I'll dig back in — I'll plan on writing another post about erlang-mode then.

I hope this was useful. I think I'll be spending a fair amount of time in erlang-mode, so I plan on getting comfortable here. Happy hacking!

No comments: