Drawing Lambdas

The other night I was watching a video on the lambda operator in Ruby 1.9.1, which can be spelled out or represented as ‘->’.  Coming from a C++ background and having dabbled in Scheme and Haskell ‘\’, I felt a little uncomfortable with this syntax.  So my first thought was that it’d be nice if you could knock off all of this ASCII tomfoolery and just use Unicode lambdas in code.  This leads to two problems though:

  • Unicode friendly keyboards don’t really exist
  • Source code tends to be strictly in ASCII

Typing Unicode

Let’s deal with the Unicode keyboard problem first…

One method to get lambdas into your code is to use digraphs in Vim.  To get a full list in the editor use the command ‘:digraph’, this will draw a matrix of every combination available.  As depicted in the screenshot below (scrolled down to Greek symbols) each column has the two-key combination, the symbol, and the Unicode decimal representation.  To insert a symbol use Ctrl-k and the two-key combination.  For example,  lambda is Ctrl-k l*.

What’s really nice about the digraphs table is that many combinations are easy to figure out.  For example, all Geek symbols are the Ctrl-k prefix and the letter followed by an asterisk.

Some are even obvious:

Diacritic Example Digraph
macron ē (letter + minus)
trema/umlaut ü (letter + colon)
cédille ç (letter + comma)
circumflex û (letter + caret)

Unicode in Action

Now all this is fun to play with a bit, but your compiler/interpreter will likely be upset with your latest additions. The few exceptions will be languages that are very friendly to Unicode strings like Go and Python.

hello_world_gr.go

package main

import fmt "fmt"

func main() {
    fmt.Printf("Γεια σας κόσμο!\n")
}

hello_world_gr.py

#!/usr/bin/env python

def main():
    print("Γεια σας κόσμο!\n")

if __name__ == '__main__':
    main()

However, when I said I wanted to see lambdas in my code I didn’t mean inside of string literals, I meant actual lambdas as keywords.  If I try to put a lambda symbol in place of the keyword ‘lambda’:

#!/usr/bin/env python

def main():
    # λ == lambda
    square = λ x : x * x
    nine = square(3)
    print(nine)

if __name__ == '__main__':
    main()

I will get the following error:

File "hello.py", line 5
square = λ x : x * x
^
SyntaxError: invalid syntax

Faking It

This leads me to my second point; you don’t really want lambdas (or any non-ASCII) in your code, but you may want to see lambdas in your editor.  In Vim, you could apply the conceal patch, which is standard in recent versions of Vim 7.3.  Conceal allows you to create syntax rules for drawing specific keywords and string matches as any symbol you like.

For instance, the Vim command:

:syn keyword Operator lambda conceal cchar=λ

will swap out the keyword lambda with the symbol λ, but not modify the text.  Moving the cursor over the lambda symbol will reveal the letters for editing.  Your compiler never has to know you were experimenting with Unicode.

.vimrc rules

There  are already many script implementations that do this kind of thing, but I  really like this solution for it’s ease of implementation.  I’ve got the following rules in my .vimrc, that I’m sure to tweak until I’m satisfied.

if has('conceal')
    if has('autocmd')
        autocmd Syntax * syn keyword Operator not conceal cchar=¬
        autocmd Syntax * syn keyword Operator lambda conceal cchar=λ
        autocmd Syntax ruby syn match rubyKeyword "->" conceal cchar=λ
        autocmd Syntax haskell syn match hsKeyword "\\" conceal cchar=λ
    endif
    hi! link Conceal Operator
    set conceallevel=2
endif

Essentially, there are four Vim syntax rules that don’t live in individual syntax files:

  • Draw not as ¬ for every file type.
  • Draw lambda as λ for every file type.
  • Draw -> as λ for all Ruby files.
  • Draw \ as λ for all Haskell files.

These rules are typically placed in syntax files, but I’m still test driving them and I don’t want to repeat the first two rules for every syntax file.  For the time being they can stay in my .vimrc where I can keep an eye on them.

Now Stretch

The whole point of going through these steps is attaining more flexibility.  Hopefully now you feel less restricted by your keyboard and your languages’ syntax.

If you feel Pascal’s not equal, <>, makes your skin crawl, you can change it with:

:syn match pascalSymbolOperator '<>' conceal cchar=≠

or to add to your .vimrc

autocmd Syntax pascal syn match pascalSymbolOperator '<>' conceal cchar=≠

For example:

while (a <> b) do WriteLn('Waiting');

is shown as

while (a ≠ b) do WriteLn('Waiting');

Everyone has completely different preferences; so if you don’t like something, change it.