Skip to content

rspeele/infix.el

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 

Repository files navigation

infix.el

Infix operators for Emacs Lisp

This library provides a macro, $, which rewrites expressions written in infix notation (with operators between their operands) to S-expressions. This lets you write some Emacs Lisp code in a more readable and concise format. For example:

    ($ x+y*3 < 15 and z%8 = 0)

expands to:

    (and (< (+ x (* y 3)) 15) (= (% z 8) 0))

Because the translation from infix notation happens during macro expansion, it can be expected to have no performance penalty on byte-compiled code, compared to writing the S-expression manually.

Doesn't require spaces

Elisp is very liberal in what it considers a "symbol" (variable name). It parses 1+2 as a symbol, strange though it is. You can actually use this like any other symbol, for example assigning it a value with (setq 1+2 37). The $ macro automatically works around this wacky feature, breaking the symbol out into the separate terms 1 + 2 before translating it to (+ 1 2). This process is called "deglobbing".

This behavior can admittedly be confusing in the presence of variables named-like-this. Because such variable names are idiomatic in Lisp, they are special-cased by the deglobber and NOT treated as subtraction unless you use spaces. That is, ($ a+b) expands to (+ a b), and ($ a - b) expands to (- a b), but ($ a-b) expands to a-b.

If you want to keep it simple at the expense of requiring spaces around every operator, you can use the $: macro instead, which does not do any mangling of symbols.

Plays nicely with s-exprs

The $ macro only rearranges the top-level terms it is applied to. Nested s-expressions are left alone, so you can do stuff like:

    ($ 1 + (read "2"))

This makes using normal elisp code within an infix expression very simple. However, it might be confusing if you want to use parentheses the way they'd be used in infix expressions in other languages: to override the default order of operations. For example, consider the expression (1+2)*3. For that you have two options:

Either use curly braces for grouping nested infix expressions:

    ($ {1 + 2} * 3)

Or just use the $ macro again in a nested s-expression:

    ($ ($ 1 + 2) * 3)

Generates efficient elisp

There is no need to worry about expressions like:

    ($ a + b + c + x + y + z)

resulting in inefficient elisp such as:

    (+ (+ (+ (+ (+ a b) c) x) y) z)

infix.el knows that some operators, like +, can have nested calls simplified and will generate the desired expression:

    (+ a b c x y z)

Lets you define your own operators

Finally, macros are also provided for declaring your own infix operators with custom associativity and precedence.

For example, to declare the symbol @ to be a left-associative operator with the same precedence as the + operator, you can write:

    (infixl (precedence +) @)

To declare it as a right associative operator, with a precedence higher than + but less than *, you would use:

    (infixr (precedence-between + *) @)

And finally, if @ can have nested calls flattened to a single call, as in the example of + above, you would use infixrf or infixlf instead of infixr and infixl, respectively.

    (infixrf (precedence-between + *) @)
    ;; ($ 1 @ 2 @ 3) now becomes (@ 1 2 3) instead of (@ 1 (@ 2 3))

For further details, consult the docstrings for $ and $:, or read the comment blocks in the source.

Enjoy.

Releases

No releases published

Packages

No packages published