Feeds:
Posts
Comments

Archive for the ‘Emacs’ Category

Terse Hashes Miscellany

This is part 4 in my terse hashes in emacs lisp series

Okay, time to wrap up with the terse hashes.

The built-in hash tables have equivalents to the perl exists and delete, but again, the argument order does not feel right to me.

Having looked at ruby a bit over the past few months, I’ve decided I like predicates ending with a question mark1 rather than a p.

(defsubst exists? (hash key)
  (not (eq (gethash key hash 'missing-key) 'missing-key)))

(defsubst del-hash! (hash key) (remhash key hash))

And the other thing I rely on a lot in perl is keys so I can choose the traversal order with sort.

(defun keys (hash)
  (let (keys)
    (maphash (lambda (k v) (push k keys)) hash)
    keys))

I need a decent less than method

(defun generic/less (val1 val2)
  (if (and (numberp val1) (numberp val2))
      (< val1 val2)
    (let ((v1 (prin1-to-string val1))
          (v2 (prin1-to-string val2)))
      (string< v1 v2))))

and then this sort of thing just works

(defvar %hash (_h { 1 2 'a 'x 5 6 10 "lemon" }))
(sort (keys %hash) #'generic/less) ;; --> (1 5 10 a)

1. Was this first in scheme?

Read Full Post »

This is part 3 in my terse hashes in emacs lisp series

Since emacs 23.2 was released the hash creation part of my _h macro is now obsolete. (or maybe not – perhaps allowing nested braces would make usage cleaner at the cost of significant complexity)? However, I suspect that is only one part of what would make emacs lisp nested data structures pleasant to use.

The other piece of the puzzle is dereferencing.

We don’t need a macro to implement the set and get functionality that _h includes so far. It was only required to prevent the braces from being evaluated.

Previously I mentioned extending the _h macro to allow for easier, or at least terser, nested hash dereferencing. The syntax I suggested would still need a macro. And I might as well leave the braces hash creation. It is unlikely my firm will upgrade to 23.2 in the next few months.

Given this nested %hash

(defvar %hash)
(setq %hash (_h { 1 2
                  'h (_h { 3 4
                           5 6
                           'h2 (_h { 1 2
                                     3 [5 6 7]
                                     'vh (vector (_h { 1 2 })
                                                 (_h { 3 4 }))
                                   })
                         })
                }))

I want (_h %hash -> 'h 'h2 'vh [1] 3) to return 4.

(It might be nice to add a nested assignment such as

(_h %hash -> 'h 'h2 'vh [1] 3 := "hello")

but the dereference will do for now.)

(defsubst h/vref (num)
  (cons 'vecpos num))

(defmacro _h (arg1 arg2 &rest args)
  (declare (indent defun))
  (cond ((eq arg1 '{) ...)
        ((eq arg2 '->)
         (let (str new-args)
           (dolist (elem args)
             (setq str (prin1-to-string elem))
             (if (string-match "\\[\\([0-9]+\\)\\]" str)
                 (let ((pair (h/vref (string-to-number
                                      (match-string 1 str)))))
                   (push (cons 'quote (list pair)) new-args))
               (push elem new-args)))
           (setq new-args (reverse new-args))
           `(h/get-value (quote, arg1) ,arg1 ,@new-args)))
        ((null args) ...)
        (t ...)))

That might be a little over the top, but it demonstrates that the macro facility does pretty much have access to the full power of the language.

The new functionality relies on a helper function, h/get-value.

(defun h/get-value (var-name variable &rest args)
  (let (retval param previous-param)
    (when (<= (length args) 0)
      (error "(_h %s -> ...) was not passed any arguments" var-name))
    (setq retval variable)
    (while args
      (setq param (pop args))
      (cond ((and (consp param) (eq 'vecpos (car param)))
             (let ((ref (cdr param)))
               (setq param (intern (concat "[" (number-to-string ref) "]")))
               (if (vectorp retval)
                   (setq retval (aref retval ref))
                 (error "%s not a vector @ %s (%s)"
                        var-name param previous-param))))
            ((hash-table-p retval)
             (setq retval (gethash param retval 'missing-key))
             (when (eq retval 'missing-key)
               (error "Can't find nested hash value %s in %s (%s)"
                      param var-name previous-param)))
            (t (error "value %s returned for param %s is not a hash in %s"
                      retval previous-param var-name)))
      (setq previous-param param))
    retval))

(macroexpand '(_h %hash -> 'h 'h2 'vh [0]))
--> (h/get-value (quote %hash) %hash (quote h) (quote h2) (quote vh) (quote (vecpos . 0)))

The problem with extending syntax like that is what if we want to use a variable to reference the vector rather than hardcoding a value like [0]. The obvious solution doesn’t work.

(defvar test-var)
(setq test-var 1)

(defsubst vec-ref (num)
  (intern (concat "[" (number-to-string num) "]")))

(_h %hash -> 'h 'h2 'vh (vec-ref test-var))

Debugger entered--Lisp error: (error "value [#<hash-table 'eql nil 1/65 0x1438680> #<hash-table 'eql nil 1/65 0x1438200>] returned for param vh is not a hash in %hash")
  signal(error ("value [#<hash-table 'eql nil 1/65 0x1438680> #<hash-table 'eql nil 1/65 0x1438200>] returned for param vh is not a hash in %hash"))

(the error message indicates there is a problem with h/get-value too but no time to fix before we went to press)

It is easier to go down to the next level – the code that the macro generates. The following performs as required.

(_h %hash -> 'h 'h2 'vh (h/vref test-var) 3)

Hopefully I didn’t offend too many senses of aesthetics there.


For reference, the full _h

(defmacro _h (arg1 arg2 &rest args)
  (cond ((eq arg1 '{)
         ;; check for empty case
         (if (eq arg2 '})
             (make-hash-table)
           ;; (_h { k1 v1 k2 v2 ... })
           (let ((rest (cons arg2 args))
                 elem tmp)
             (while (not (null rest))
               (setq elem (pop rest))
               (when (not (or (eq elem '}) (eq elem '=>)))
                 (push elem tmp)))
             (setq tmp (reverse tmp))
             `(literal-hash ,@tmp))))
        ((eq arg2 '->)
         (let (str new-args)
           (dolist (elem args)
             (setq str (prin1-to-string elem))
             (if (string-match "\\[\\([0-9]+\\)\\]" str)
                 (let ((pair (h/vref (string-to-number
                                      (match-string 1 str)))))
                   (push (cons 'quote (list pair)) new-args))
               (push elem new-args)))
           (setq new-args (reverse new-args))
           `(h/get-value (quote, arg1) ,arg1 ,@new-args)))
        ((null args)
         `(gethash ,arg2 ,arg1))
        (t (let ((val (car args)))
             `(puthash ,arg2 ,val ,arg1)))))

Read Full Post »

This is part 2 in my terse hashes in emacs lisp series

Another thing I like about Perl data structures, is that once I have stuffed all my data in there, I can easily see what it looks like with Data::Dumper.

my $data = {
    list1 => [
        { x => 'y' },
        { a => 'b' },
        # etc ...
    ],
    # etc ...
}

print Dumper($data);

And the result is:

$VAR1 = {
          'list1' => [
                       {
                         'x' => 'y'
                       },
                       {
                         'a' => 'b'
                       }
                     ]
        };

This is a big help with Exploratory Programming as you can see if you’re stuffing values in the right place.

You might be surprised to learn that I want the same functionality in Emacs Lisp.

(defun hash-dumper (hash &optional indent)
  (when (null indent) (setq indent 0))
  (let (lines indent-string)
    (setq indent-string "")
    (dotimes (i indent) (setq indent-string (concat " " indent-string)))
    (maphash (lambda (k v)
               (if (hash-table-p v)
                   (push (format "%s =>\n%s"
                                 k (hash-dumper v (+ indent 2))) lines)
                 (push (format "%s => %s" k v) lines)))
             hash)
    (concat (format "%s{" indent-string)
            (mapconcat #'identity lines (format "\n%s " indent-string))
            "}")))

And the result…

(defvar %hash)
(setq %hash (_h { 1 2
                  'h (_h { 3 4
                           5 6
                           'h2 (_h { 1 2
                                     3 [5 6 7]
                                     'vh (vector (_h { 1 2 })
                                                 (_h { 3 4 }))
                                   })
                         })
                }))

;; (insert (format "\n%s" (hash-dumper %hash)))
{h =>
  {h2 =>
    {vh => [#<hash-table 'eql nil 1/65 0x17cce80> #<hash-table 'eql nil 1/65 0x16f0a00>]
     3 => [5 6 7]
     1 => 2}
   5 => 6
   3 => 4}
 1 => 2}

Not bad, but not quite right. Fixing the problem with lists of hashes is left as an exercise for the reader.

Read Full Post »

This is part 1 in my terse hashes in emacs lisp series

One thing I really love about Perl is the easy and natural syntax for deeply nested data structures. I can make a hash of lists of hashes without a second thought.

(Okay, okay, Ruby and Python are equally good or even slightly better here, but I’m thinking about in comparison with emacs lisp, and C++ and Java…)

my $data = {
    list1 => [
        { x => 'y' },
        { a => 'b' },
        # etc ...
    ],
    # etc ...
}

In contrast, the syntax for dealing with hashes in emacs lisp is extremely verbose. Not only that, but for me, the arguments are the wrong way round. In object based programming, the object is always the first argument.

(make-hash-table)
(puthash <key> <value> <hash-table>)

When I came across the Clojure syntax for hash sets using #{ ... } I thought what a good idea. Unfortunately, emacs lisp doesn’t have reader macros. Let’s see what happens when I try it with a function.

(defun hash-set (opening-brace &rest args)
  nil)

(hash-set { 1 2 3 4 })

The result tells us that emacs is trying to evaluate the value of { as a variable before passing it to the function.

Debugger entered--Lisp error: (void-variable {)
  (hash-set { 1 2 3 4 })
  eval((hash-set { 1 2 3 4 }))
...

Fortunately, in emacs lisp, we can delay the evaluation of the arguments using a macro. I use the same macro to make setting and retrieving individual hash values easy too.

(defun literal-hash (&rest args)
  (let ((hash (make-hash-table)))
    (while args
      (let* ((key (pop args))
             (val (pop args)))
        (puthash key val hash)))
    hash))

(defmacro _h (arg1 arg2 &rest args)
  (cond ((eq arg1 '{)
         ;; check for empty case
         (if (eq arg2 '})
             (make-hash-table)
           ;; (_h { k1 v1 k2 v2 ... })
           (let ((rest (cons arg2 args))
                 elem tmp)
             (while (not (null rest))
               (setq elem (pop rest))
               (when (not (or (eq elem '}) (eq elem '=>)))
                 (push elem tmp)))
             (setq tmp (reverse tmp))
             `(literal-hash ,@tmp))))
        ((null args)
         `(gethash ,arg2 ,arg1))
        (t (let ((val (car args)))
             `(puthash ,arg2 ,val ,arg1)))))

Even nested hashes work nicely (I might be betraying my perl biases here!)

(defvar %hash (_h { 1 2 3 (_h { 1 2 3 4 } )))
(_h (_h %hash 3) 1) ;; ==> 2

Okay, retrieval is a little awkward, but I could add some more syntax to _h to make the following work.

(_h %hash -> 3 1)

That is left as an exercise for the reader.

Update: Hi atomicrabbit, I couldn’t figure out how to do the syntax highlighting in the comment so I have included my reply below.

I didn’t know about the #s(make-hash ...), so that looks pretty cool. I found a mention in the Elisp Cookbook. I couldn’t get it to work though unfortunately. Any ideas?

(emacs-version)
;; "GNU Emacs 23.0.60.1 (i386-mingw-nt6.0.6000)
;;  of 2009-01-12 on LENNART-69DE564 (patched)"
(read (prin1-to-string (make-hash-table)))
(read "#s(hash-table data ('key1 'val1 'key2 'val2))")
Debugger entered--Lisp error: (invalid-read-syntax "#")
  read("#<hash-table 'eql nil 0/65 0x143c880>")
Debugger entered--Lisp error: (invalid-read-syntax "#")
  read("#s(hash-table data ('key1 'val1 'key2 'val2))")

Read Full Post »

Removed from Planet Emacsen

Now that I write mainly about p.erl I had considered not publishing this post, but I’m curious to know the reason if any and email to the planet emacsen maintainer, Edward O’Connor, has gone unanswered.

A couple of years ago when I started blogging about emacs I asked to be included in planet emacsen. And now I have been removed. What can be the reason for that I wonder.

Well, I have just come back from a blogging break. Between my post on sorting records with emacs in August 2009 and my post on Enablers and Obstructors in March 2010, there were almost 7 months. But the latest post in Amortized Analysis (a blog that hasn’t been removed from planet emacsen) was 4th January 2008. That is more than 2 years ago.

Maybe I’m not that relevant anymore. I have posted mainly P.erl posts since my break. But I do still do emacs stuff, e.g. Directory Aliases Revisited and Programming with Types. And Alexandre Vassalotti’s most recent Emacs post was September 2007.

Or was it the back and forth with Ian Eure (and to a lesser extent, Aaron Hawley) about my Emacs Database Mode. Did someone ask for me to be removed?

Anyway, whatever the reason, it has been done. What solution do I have? I have created a yahoo pipe called Better Planet Emacs which you can subscribe to. It filters a lot of the non-emacs related posts out so for me at least it is better than stock planet emacs. If you want to copy it and customise it for your own use you should go here.

Read Full Post »

Emacs Has QWAN

The Preamble

I enjoy programming in Perl. There, I said it. And, although a lot of the stuff I write could easily be written in Emacs Lisp, I generally reach for Perl to solve most of my programming problems. However, if I had to choose between Perl and Emacs disappearing, I’d choose Perl any day of the week and twice on Sunday.

The reason is that there isn’t any competition in the emacs space1. Vim, Visual Studio and Eclipse are not acceptable substitutes. But if I want a dynamically typed langugage with good syntactical support for arrays, hashes and regular expressions and loads of libraries I know where to find Ruby or Python.

Q. Why not switch to Ruby today?
A. I enjoy programming in Perl

What makes Emacs so great?

(or what would I need to switch from Emacs to another editor)

Many people put it as Emacs has QWAN (the quality without a name), but that doesn’t really help to quantify things. Saying that all of the features work very nicely together is true, but also not that helpful. Let me try and point out a few things.

(If the c2 link above isn’t working, try the Bing cache).

Keystrokes are bound to functions

…and it is all very discoverable. If I want to know what a given keystroke does, I just press C-h k <key> and it tells me the function that calls. For example, arrow key calls forward-char. Now, say I want to make a function that needs to move forward a number of characters, I know what the function is called.

The utility of this discoverability in making composite functions cannot be overstated. You might think that macros are equally good, but what if I want a function that persists between sessions. For my line duplication function I glued together functions found with C-h k.

Okay, new utilities, great but not that impressive.

What about fixing stuff with the editor that you just don’t like. For example, recently I had a problem where <page down> went to the beginning of the line rather than remembering the current column position. You might be thinking a proper editor wouldn’t do that, or it isn’t really a problem, but you can’t imagine how annoying that was after the first ten times.

Anyway, what I did was… I fixed it. With C-h k I found that the command was scroll-up and I wrote a wrapper function that remembered the current column (alternatively I could have used advice). Saved my blood pressure and took around 5 minutes.

To summarise:

  • Key strokes / key chords call functions (which can be user-defined)
  • New functions can be created within the editor at any time
  • any key / key chord can call any function
  • information about the function can be viewed

Okay, you’re not convinced. Vim can do that, albeit with a much less pleasant language (or with perl, ruby, python, etc. if you’ve compiled a fat vim)

Editor Tabs

Tabs are not the right mechanism to deal with hundreds of open files. Emacs (together with ido) works beautifully. Generally I’ll have a couple of hundred files open with different file types and I’ll use progressive filtering to first find the perl files and then narrow down the file I wanted. Very quick and very nice. I’ve spent hours scrolling through tabs in Visual Studio and it was not fun.

Keymaps

So all your keys are bound to various useful commands. M-e steps forward to the next sentence nicely. But then you’re editing lisp (or perl) and sentence doesn’t mean much. What does emacs do?

In this case it has a keymap hierarchy. The global keymap defines a bunch of keys which can be overridden by keys defined in the major mode keymap. These can be added to with keys defined in one or more minor mode keymaps.

Comint

Comint is an awesome bit of kit. Out of the box, Emacs provides fantastic support for interacting with asynchronous processes. Comint codifies a lot of the functionality you would want to make a decent REPL for an external interpreter. Because this is one of the more tricky interactions to manage, it is an excellent API for dealing with any external process.

A while ago I wrote an article about a comint based stock price subscriber which demonstrates a few comint features.

Take a look at the interaction with gdb following M-x gdb-many-windows. It looks like an IDE no?

Emacs Applications

Some people have developed some impressive applications in emacs.

  1. Org Mode
  2. Emacs Muse
  3. SLIME (A full-featured Lisp IDE)

And my own Emacs Database Mode

Which in turn is based on the excellent sql-mode.


1. Apart from XEmacs of course.

Read Full Post »

Hang on, that should be Vim vs Emacs right? No.

I have been blogging for the Perl community I have been writing Perl blog posts for around 6 weeks now. Prior to that, I wrote mostly Emacs related blog posts for around 18 months. My vast experience puts me in a great position to compare them.

Emacs blogging

Back when I wrote about Emacs I averaged a couple of posts a week and around 200 visitors a day. Better still, I got several comments for each post, pointing out things I had got wrong, things I could improve or alternative techniques.

200 visitors isn’t many, but it was plenty for me. I was paid for my blogging effort in comment currency.

I suspect the reason I got the comments was that I never had much competition in the emacs hints and tips space. The main ones were:

Of these, only emacs-fu kept grinding out the handy tips, week in week out.

Interestingly, emacsblog reports 3379 readers by feedburner which indicates a decent level of interest in emacs hints and tips.

There was only one real place to pick up emacs news – Planet Emacsen. My posts would hang around for a week or more and I would pick up pretty much all the readers who were interested as well as probably quite a few who weren’t.

Perl blogging

With my Perl blog posts, I struggle to keep 100 visitors a day and I need to post every other day to get that many. Why the difference? I suspect it is a combination of things.

  • If you want to read about perl, you can read the gurus in the community – the Miyagawas, the Tim Bunces, the Curtis Jewels. And there’s hundreds more perl gurus blogging. Okay, maybe 10 more.
  • There are multiple perl news sources. I listed a few here.
  • If you want to improve your perl-fu there is IRC or Perl Monger groups. Emacs in contrast had fewer options.
  • There are more perl bloggers, so your post disappears off the Ironman aggregation pretty quickly.
  • Six weeks may not be enough to build up a following.
  • There are more areas of perl to be interested in. Maybe no-one else wants to know about writing AnyEvent TCP servers.

It could also be that the quality of my writing is poor. But one of you guys would tell me, right?

Why does this matter?

Blogging has to have some value to me, otherwise I might as well watch TV. I do get something out of it even if there are no readers – I’m able to find my fantastic code snippets as long as I have access to the internet. But the lack of input means this doesn’t really offset the effort to write a story around each post. And these days with github et al there are easier and better ways to get your code out there.

Okay, no worries, you’re thinking, if Jared stops blogging about perl (not that I’m thinking of doing so) no-one loses anything. But maybe my experiences is why the level of blogging activity is low compared to the relative size of the community.

And maybe it just doesn’t matter.

Read Full Post »

« Newer Posts - Older Posts »

Follow

Get every new post delivered to your Inbox.