Skip to main content

Politics, Programming, Data and the Drogulus

(This article is based upon a short talk I gave at Opentech 2013.)

Drogulus logo

I'm going to describe the drogulus: a programmable peer-to-peer data store that I've been hacking on in my spare time.

The problem I have is a growing unease with the current state of the web. This unease can be summed up in three ways:

  1. On the web, users are no longer in control of their data or online identity. They're locked in to websites that act as walled gardens of data each of which requires different credentials in order to log in. Once logged in there is often no way to extract data. Furthermore, how can we tell who's who? Is user X on Twitter the same user X on Facebook?
  2. Programmers have to build stuff on the web using complicated and quirky technology defined in a top down manner by committee. Just watch any web developer grimace if you mention OAuth, CORS, Javascript date objects or (dare I say it) Internet Explorer.
  3. There are many inadvertent points of control, lock-in and authority built in to the web - each of which is a potential mechanism for dis-empowerment and exploitation. Just look at the great firewall of China, the censorship of the Piratebay here in the UK or the kerfuffle over payment to Wikileaks.

The beautifully simple, open and decentralised hypertext system envisioned by Tim Berners-Lee has grown in to a closed, centralised and complicated monster beholden to dodgy commercial, political and legal manipulation. More worryingly still, our data is analyzed by companies, sold via targeted advertising or handed over to governments without our consent.

Unfortunately, many aspects of today's web are contrary to a concept that is very important to me: autonomy.

When someone is autonomous they are self-directing, free to act of their own accord and lack imposition from others. Autonomy also suggests intelligence and awareness enough to be able to enjoy and make use of such freedom. Furthermore, such intelligence entails decision making so people become accountable for their actions. Autonomy is also the opposite of such undesirable states as tyranny, slavery, ignorance and apathy.

I asked myself, how would software designed to promote autonomy function? I started to hack and the drogulus was born.

The drogulus is a speculative exercise in peer-to-peer decentralisation, a political statement (it promotes a certain point of view about technology's role in society) and is a place for me to explore fun ideas that have been knocking around in my head for a while.

I tell myself, "it'll all come to nothing" but I'm having too much fun to stop, so I want to tell you about the drogulus to give you a sense of why I find it so fascinating.

So, how is the drogulus designed to promote digital autonomy?

It's a global federated, decentralized and open data store that can be programmed by anyone. Identity and provenance is ensured by cryptographically signing digital assets.

Being federated (the system consists of many independent but collaborating entities) and decentralized (no entity is more important than the others) ensures users are free from choke points of authority that may be used to control access to data and usage of the system.

Being an open system means all users are free to contribute, change, enhance and expand the system without prejudice.

Being programmable means users can do something with the data stored within the drogulus. It's a sort of distributed programming environment. Imagine it as a re-configurable SETI@home on steroids: by running a node in the drogulus network you are sharing a small amount of your potential computing power with everyone else on the network.

By using public key cryptography the drogulus ensures the provenance of the data and that it has not been tampered with. Importantly, there is no central authority to prove who's who. Identity is built on the far more humane mechanism of a web of trust.

So how does it work? Well, there are three simple core components:

  • A distributed hash table (DHT) that provides the data store and allows users to find each other.
  • Trust and identity enforced by the afore mentioned cryptographic signing of digital assets.
  • Logos (λόγος), a simple Lisp like programming language for asynchronously working with data stored in the distributed hash table.

Each component promotes autonomy in the following ways:

A distributed hash table works like a sort of peer-to-peer dictionary: a unique key is used to identify a value. In the case of a traditional dictionary, the key is a word and the value is its definition. Being a data store, the distributed hash table allows users to create, retrieve, update and delete their own keys and associated digital values.

The hash table is distributed because it is split in to the equivalent of many volumes of a traditional dictionary. Each person who ever uses the dictionary has a copy of just one volume with many copies of the same volume being distributed to many different users.

Users keep track of which of their friends on the network hold what volume. Users interact with the distributed hash table by contacting the friend with the correct volume for the desired item. If they don't know anyone with the right volume they play a sort of six-degrees-of-separation game with their friends until someone with the correct volume is found.

Distributed hash tables also share an interesting property with Bittorrent: the more popular an entry is the more widespread it becomes, thus improving performance since popular items are easier to find.

The drogulus implements a version of the Kademlia distributed hash table algorithm. The innovation the drogulus brings is that keys and values are signed in such a way that their provenance can be proven and content shown to be intact. Furthermore, users cannot interfere with each other's items stored within the distributed hash table unless they have access to the same private key.

Items are self contained and any that do not pass the cryptographic checks are ignored and nodes on the network that attempt to propagate such values are punished by being blocked by their peers.

Programming the drogulus is done via Logos, a homoiconic language: this means code and data are the same thing in Logos. This has the interesting mind-bending side effect that Logos programs can rewrite other Logos programs in order to extend the Logos programming language itself. This is an important property: users have the autonomy to grow the Logos programming language to suit their own needs.

Since Logos programs are also data they are stored as values within the distributed hash table so users can re-use each other's code.

They run in asynchronous "ensembles" on other nodes in the drogulus network. The result is delivered when the ensemble eventually arrives at a consensus. To protect peers, Logos programs are sandboxed and intentionally limited in terms of time (how long they can run for) and space (how much memory may be used).

At each point in hacking together the drogulus I've tried to build a solution whose outcomes reflect my ethical and political considerations: a focus on autonomy and openness and the removal of authority and choke points.

Unfortunately, the drogulus is unfinished! Currently, the distributed hash table is almost done, the cryptographic layer is finished and Logos is in the advanced planning stages with some experimental code written.

It's early days and I realise that there are potential contradictions and problems that I've not worked out, nor is there anything useful that can be achieved with the drogulus at this moment in time. Because I'm working at such an abstract level it's hard for me to comprehend what use others may find for a programmable peer-to-peer data store. That's why I wanted to present the drogulus in its current incomplete state: to gauge what sort of reaction (if any) it might get.

I'll finish by pointing out that in 1996 William Gibson described the web as merely the test card for 21st century technology. I'd like to think we can do better than the web. Thinking outside its confines has been a liberating experience and I'd encourage everyone to do the same. Obviously the drogulus is the rough and ready result of such pondering by me.

We'd only have ourselves to blame if we don't imagine and build something better than the test card that is the web. After all, if there's one thing that the web has taught us, it is that engineering software is a far more useful, tangible and easier agent of change than traditional means of political engagement.

The code is on GitHub and I've created a simple website that explains things further. If you have any questions please drop me an email.


EDIT: Most of the technical questions I was asked resulted in me saying, "I don't know". I consider this a good thing. It was interesting that someone picked up on etymological fun I've been having with this project. ;-)

EDIT 2: I've attempted to give considered answers to the questions raised at Opentech in this blog post.

Image credits: © the author.

App for Doctors - Do I Treat This Immigrant?

I've just built (in all of 20 minutes) a helpful cross-platform website that automatically detects if a doctor in the UK should treat an immigrant asking for treatment. It's a fully responsive HTML5 application that works with *all* devices that connect to the web (although it's untested on IE6).

The BBC reports that, "Migrants' access to the NHS would be restricted" after the Queen's speech of 8th May 2013. Jeremy Hunt, health secretary, has identified that immigrants are clogging up UK hospitals.

Obviously, this application can't come soon enough:

The source code can be found here (pull requests welcome!):

For the "BIG DATA" people, there's even a RESTful API: JSON or XML.

Taking the Long Term View

The British Museum is one of my favourite places because it forces me to take on a perspective of 5000 years or more. Take the Mesopotamian clay tablet shown below: it records the allocation of beer by administrators in the city of Uruk. The symbol representing beer is apparently an upright jar with a pointed base, amounts are notated by circles and semi-circles and, at the bottom left, there is a figure drinking from a bowl.

Mesopotamian tablet

It's about 5100 years old. Now, pause for a moment to consider its age.

The difference in time between today and the era of Julius Caesar and Cleopatra is 1000 years less than the period between the creation of the Mesopotamian tablet and the era of Caesar and Cleopatra. Put simply, Caesar and Cleopatra are closer in time to us (by 1000 years) than they are to the Mesopotamian scribe who recorded the allocation of beer to citizens of Uruk.

It is intriguing that the tablet is political in nature, an instance of a new technology and of economic interest. Not only is it evidence of the machinations of the state in Uruk but it demonstrates how a new technology (writing) changed the capabilities of such a state: for the first time it was possible to keep records and thus run a bureaucracy on a large scale. Furthermore, it records receipt of payment requiring concepts such as balance, debt and a measure of value (in beer).

Such concepts (writing, state bureaucracy and fundamental economics) are unremarkable in today's world, making it difficult for us to appreciate how important, strange or unusual they must have seemed when they first appeared. I wonder what important, strange or unusual aspects of our time will be unremarkable to our descendants. Furthermore, what aspects of our lives that seem fixed today will be completely different 5000 years hence?

Guessing the future is a fool's game. As Alan Kay famously stated,

"The best way to predict the future is to invent it."

Something from today that "invents the future" is programming, and I'm guessing the Lisp program from 1960 copied below is our Mesopotamian tablet for future generations:

(shadow '(trace untrace))
(defun trace   (functions) (eval `(cl:trace   ,@functions)))
(defun untrace (functions) (eval `(cl:untrace ,@functions)))

(defun define (definitions)
  (dolist (def definitions)
    (eval (if (and (consp (second def)) (eq 'lambda (car (second def))))
              `(progn (defun        ,(first def) ,@(cdr (second def)))
                      (defparameter ,(first def) ,(second def)))
              `(defparameter ,(first def) ,(second def))))))

(defun stop (arguments) (throw 'driver-end-of-deck nil))
(defun fin  (arguments) (throw 'driver-end-of-deck nil))
(defun test (arguments) (princ arguments) (terpri))

(defun driver (path)
  (with-open-file (cards path)
    (catch 'driver-end-of-deck
      (loop (let ((first-char (read-char cards)))
              (if (char= #\* first-char)
                  (read-line cards)     ; comment
                    (unread-char first-char cards)
                    (let* ((command   (read cards))
                           (arguments (if (member command '(stop fin test))
                                          (list (read-line cards))
                                          (read cards))))
                      (print (apply command arguments))))))))))

Despite this code being more than 50 years old, it is still understandable to anyone who has read my recent Lisp article. Furthermore it forces me to wonder what the computational world will be like in 5000 years. I hope the world wide web will be long gone and replaced with something much more capable and better engineered and I guess that new computer architectures will arise to replace the Von Neumann / Harvard based models in current use.

Perhaps the final word should be another Alan Kay quote:

"I believe that the only kind of science computing can be is like the science of bridge building. Somebody has to build the bridges and other people have to tear them down and make better theories, and you have to keep on building bridges."

Image credits: Mesopotamian tablet © Trustees of the British Museum

Programming Minecraft on the RaspberryPi

Minecraft is a sort of digital Lego. Players explore a blocky computer generated world and have the ability to build new terrain, buildings and other features. Many users have generated creative and complicated structures within their games by carefully placing individual bricks (just like Lego). A quick Google image search for Minecraft will return lots of amazing results.

The RaspberryPi is a cheap computer designed to encourage kids (of all ages) to learn how to program. Apparently, the "pi" part of the name is a misspelled reference to the Python programming language - the RaspberryPi's principal programming language for education.

Minecraft is amazingly popular among kids (my own included). I guess, like Lego, it's the potential for creative generative play that is so appealing. Wouldn't it be great if there were a version of Minecraft that you could program in Python that ran on the RaspberryPi..?


I'm currently at PyconUS 2013 in California, every attendee has been given a RaspberryPi and there's a RaspberryPi lab in which attendees are encouraged to try their new piece of kit. I just spent a fun morning programming Minecraft with Python. What follows is a quick "how to" guide to get you started.

I'll assume you've got a RaspberryPi to hand and that it's connected to the internet. (If you're unsure how to do this I suggest you visit the main RaspberryPi website for more information.)

First you should download the RaspberryPi version of Minecraft and follow the instructions at the web page to which I just linked.

Next, once you have Minecraft running on your RaspberryPi I suggest you play for a while. Create a world and have a look around. Here's a run-down of the commands you can use:

  • Keyboard
    • W,A,S,D - Move (or navigate inventory)
    • SPACE - Jump, double tap to start/stop flying, hold to fly higher
    • SHIFT - Sneak, hold to fly lower
    • E - Open inventory
    • 1-8 - Select inventory slot item to use
    • ESC - Show/hide menu
    • TAB - Release mouse without showing menu
    • ENTER - Confirm menu selection
  • Mouse
    • Steer - Look/turn around
    • Left mouse button - Remove block (hold)
    • Right mouse button - Place block, hit block with sword
    • Mouse wheel - Select inventory slot item to use

Cool huh..?

But wouldn't it be fun to be able to program and automate the manipulation of the game world with Python..?

Here's how to get started...

Open a terminal and change in to the Minecraft directory (mcpi) within which you'll see a child directory called api within which is yet another called python. From within the python directory start Python by typing, python.

Now, type in the following:

>>> from mcpi import minecraft
>>> mc = minecraft.Minecraft.create("")
>>> mc.postToChat("Hello, World!")

You should see the message Hello, World! pop up in the Minecraft world. Congratulations, you've just programmed Minecraft!

The first command imported all the things that Python needs to talk to the Minecraft game. The second line creates an object called mc that represents a connection to your game. The third line sends the chat message to the game.

How about building things within the Minecraft world..? Check this out...

>>> from mcpi import block
>>> mc.player.getTilePos()
>>> mc.setBlock(38, 0, -38,

On the first line I import information Python needs about the blocks that you can place within the Minecraft world. Next, I ask the game where in the world my player is located. The game responds with an x, y and z based location expressed as a vector. Finally, I use the setBlock method to place a stone brick on an adjacent square. If you take a look around you'll see it right next to you!

Actually, you will see different results to me because your player will be stood in a different location. See if you can change the final line to place a block close to your own player's location.

That's it (for now) and covers pretty much all I found out in the first 15 minutes of hacking about. If you want to explore the API further I suggest you look at the mcpi_protocol_spec.txt file in the mcpi/api/spec directory.

Personally, I think this is a gift horse that teachers everywhere should be looking at in the mouth.

I'll blog some more about this when I get back to the UK.

Lisp ~ Concise and Simple

(As with all "concise and simple" articles I assume no prior knowledge of the subject and keep the length to less than 1500 words.)

Lisp Alien

Lisp is a beautiful programming language, famous for its hidden depths that lead to moments of kensho. I want to give you a sense of why I believe this.

Lisp enlightenment

For me, Lisp's beauty is revealed when its simple core concepts lead to moments of sudden insight and shifts of perspective. Lisp's simplicity begins with its syntax (how it is written): a simple notation that anyone can understand.

Lisp expressions are either atoms or lists (Lisp stands for LISt Processor).

Here are five atoms:

foo bar baz 123 "Hello World"

Atoms are sequences of characters. The penultimate atom is a number and the final one is a string (enclosed in quotes).

Here's a list:

(ham eggs bacon sausages beans)

A list is bounded by parenthesis. Lists can contain other lists:

((soup salad garlic-mushrooms)
 (roast-beef chicken-casserole vegetable-lasagne)
 (cake fruit jam-pudding))

The list above contains three items. Each item is itself another list containing three atoms. I've split the contained lists over three lines to aid readability.

Lisp's semantics (that define what the syntax means) are equally simple:

  • Code is written as lists that are evaluated by Lisp to produce results.
  • Comments begin with a semi-colon and are ignored by Lisp.
  • Lists and atoms that are "quoted" are evaluated as data.
  • Anything else is evaluated as a form ~ a list starting with an atom that Lisp understands (telling it to do something).

Comments are natural-language annotations added to the code by programmers. They're meant to help humans work out how the code works:

; This is a comment in Lisp

Quoting is a simple concept: it's the difference between quoting and "quoting" - the former is a word that means something whereas the latter refers to the word itself. To quote something, append a single quote (') to it. Here's a quoted list:

'(ham eggs bacon sausages beans)

Lisp evaluates this as just a list of atoms:

(ham eggs bacon sausages beans)

Here's an example of a form:

(+ 1 2 3)

When Lisp evaluates a form it's told to do something to produce a result. In this case, the result is 6.

If you guessed the result correctly then you've figured out prefix notation: the command comes first (in this case the atom representing the operator for summing numbers) and is followed by its arguments (the things the operator uses to generate the answer).

Can you work out the answer to the following?

(+ 1 (- 5 (+ 2 3)))

If you answered 1 then you've worked out the order in which Lisp evaluates nested expressions - it starts from the inner most expression before evaluating the enclosing outer expressions.

Here's how Lisp evaluated the example above:

(+ 1 (- 5 (+ 2 3)))
(+ 1 (- 5 5))
(+ 1 0)

Usually, the first item in a form (the operator) is the name of a function. A function is a discrete block of code that receives input (its arguments) and returns a result. In the examples above we used the functions that sum and subtract numbers. Lisp comes with many useful built-in functions including a special one for creating new functions.

I want to describe some fundamental Lisp functions; these will allow me to reveal a surprise at the heart of Lisp1.

The quote function is a long version of quoting mentioned above. The example below is equivalent to the abbreviated version '(foo bar baz):

(quote (foo bar baz))
(foo bar baz)

The atom function returns the atom t (representing true) if its argument is an atom. Otherwise it returns nil (representing false):

(atom 'foo)
(atom '(foo bar baz))

The eq function returns t if the two arguments have the same value. Otherwise it returns nil:

(eq 'foo 'foo)
(eq 'foo 'bar)

The car function expects its argument to be a list and returns the first item therein:

(car '(foo bar baz))

The cdr function (say kud-r) expects its argument to be a list and returns everything after the first element:

(cdr '(foo bar baz))
(bar baz)

The cons function expects two arguments, the second of which must be a list. It returns a new list containing the first argument followed by the elements in the second argument:

(cons 'foo '(bar baz))
(foo bar baz)

The cond (short for conditional) function takes any number of lists as arguments. Each list must contain two items: a form that evaluates to either t or nil and some other expression. Each list is evaluated in order until a form returns t at which point the other expression in the list is evaluated and returned by cond :

(cond ((eq 'foo 'bar) 'first)
      ((atom 'baz) 'second)
      ((atom 'qux) 'third))

In the example above, the first eq function evaluates to nil, whereas the second atom function is true. Therefore, the second element of the list containing the atom function is returned as the result. Although the third atom function is also true, it is ignored. This is somewhat similar to if ... elif statements in other programming languages.

The lambda function is used to create user defined functions. It expects two lists as arguments: the first contains named place-holders for the new function's arguments, the second contains the form to be evaluated to generate the new function's result:

(lambda (x y) (cons x (cdr y)))

Notice how the argument names are used in the evaluated form to refer to the values that may be passed in to the new function. This can be demonstrated by defining then immediately calling a function like this:

((lambda (x y) (cons x (cdr y)))
 '(foo bar baz))
(qux bar baz)

The value of x becomes the atom qux and y becomes the list (foo bar baz). It's useful to name new functions. Unsurprisingly, there is a way:

(defun replace-head (x y) (cons x (cdr y)))
(replace-head 'qux '(foo bar baz))
(qux bar baz)

The function replace-head is defined (defun) then used to give the result (qux bar baz). Being able to name a function makes it possible for the function to refer to itself. This very important behaviour is called recursion. Assuming <= means less than or equal and * means multiply, can you tell how the following recursive example works?

; Returns the product of all positive integers less than or equal to n.
(defun factorial (n)
  (cond ((<= n 1) 1)
         ('t (* n (factorial (- n 1))))))
(factorial 4)

After a useful comment a function called factorial (that takes a single argument called n) is defined. The function checks if n is less than or equal to 1 and if so returns the number 1. Otherwise, it returns n multiplied by the result of calling factorial (i.e. itself) of n minus 1. Finally, the new function is tested with the number 4, producing the result 24.

Recursion is when the function returns n multiplied by factorial of n minus 1. The value of n keeps decreasing and is fed back in to the factorial function until n equals 1, at which point the number 1 is returned to complete the following chain of arithmetic: 1 × 2 × 3 × 4

Here's the surprise: given the fundamental functions described above, it is possible to write a Lisp in Lisp. When Lisp evaluates an expression, a list (the code) is itself an argument to a function that returns the result of evaluating the code. In Lisp, this function is called eval and it is possible to define such a function using only the features described above.

First, some shorthand functions need defining: cxr and list. The cxr set of functions replace the x with a sequence of as or ds to indicate a corresponding sequence of nested car or cdr calls. For example,

(cadr a)

is shorthand for:

(car (cdr a))
returning the second element of a.

The list function returns a list containing a given sequence of expressions:

(list 'a 'b 'c)

is equivalent to:

(cons 'a (cons 'b (cons 'c '())))

which returns the list: (a b c). In many Lisp implementations the list function is abbreviated to ` (backquote). Remember this, we'll use it later!

Next, we define some useful helper functions:

; tests if the argument is an empty list.
(defun null? (x)
  (eq x '()))

; returns t if both arguments also return t - otherwise returns nil.
(defun and. (x y)
  (cond (x (cond (y 't) ('t nil)))
        ('t nil)))

; returns t if the argument returns nil, or nil if its argument returns t.
(defun not. (x)
  (cond (x nil)
       ('t 't)))

; concatenates two lists.
(defun append. (x y)
  (cond ((null? x) y)
        ('t (cons (car x) (append. (cdr x) y)))))

; pairs up the elements of two lists of the same length.
; e.g. (pair. '(x y z) '(a b c)) -> ((x a) (y b) (z c))
(defun pair. (x y)
  (cond ((and. (null? x) (null? y)) '())
        ((and. (not. (atom x)) (not. (atom y)))
         (cons (list (car x) (car y))
               (pair. (cdr x) (cdr y))))))

; takes an atom x and list of pairs y and returns the
; second element of the first list in y whose first
; element is x.
; e.g. (assoc. 'x '((x a) (y b))) -> a
(defun assoc. (x y)
  (cond ((eq (caar y) x) (cadar y))
        ('t (assoc. x (cdr y)))))

Notice how the final two functions use recursion as the mechanism for looping over lists.

Here's the eval function:

; Lisp's eval function written in Lisp.
; Takes Lisp source code as a list, e, and a context of arguments,
; a, and returns the result of evaluating e in context a.
(defun eval. (e a)
    ((atom e) (assoc. e a))
    ((atom (car e))
        ((eq (car e) 'quote) (cadr e))
        ((eq (car e) 'atom) (atom (eval. (cadr e) a)))
        ((eq (car e) 'eq) (eq (eval. (cadr e) a)
                              (eval. (caddr e) a)))
        ((eq (car e) 'car) (car (eval. (cadr e) a)))
        ((eq (car e) 'cdr) (cdr (eval. (cadr e) a)))
        ((eq (car e) 'cons) (cons (eval. (cadr e) a)
                                  (eval. (caddr e) a)))
        ((eq (car e) 'cond) (evcon. (cdr e) a))
        ('t (eval. (cons (assoc. (car e) a)
                         (cdr e))
    ((eq (caar e) 'label)
      (eval. (cons (caddar e) (cdr e))
             (cons (list (cadar e) (car e)) a)))
    ((eq (caar e) 'lambda)
      (eval. (caddar e)
             (append. (pair. (cadar e) (evlis. (cdr e) a))

; A recursive function to evaluate a conditional.
(defun evcon. (c a)
  (cond ((eval. (caar c) a)
         (eval. (cadar c) a))
        ('t (evcon. (cdr c) a))))

; A recursive function to evaluate a list.
(defun evlis. (m A)
  (cond ((null? m) '())
        ('t (cons (eval. (car m) a)
                  (evlis. (cdr m) a)))))

The eval function takes two arguments: e (the expression to be evaluated) and a (a list of pairs representing the named parameters passed in as arguments). It evaluates e in the context of a. The function body is relatively simple: a conditional containing four clauses for handling atoms, the fundamental functions, cond statements and the lambda function. The clause for the fundamental functions is itself a conditional containing sub-clauses for each fundamental function. The last two clauses call out to the recursive evcon and evlis functions that evaluate conditionals and lists respectively.

Notice how eval treats the incoming Lisp source code as a list to be manipulated like any other data structure. When a language's code is also merely data (as it is for the eval function above), it is called homoiconic. This introduces the potential for yet another mind bending capability: it is possible to change Lisp from within Lisp since all code is written as lists and Lisp is a LISt Processor. Therefore, Lisp is able to transform and change its own source code in order to add unforeseen features.

The macro is what makes this possible. Macros look a lot like functions but are different in two ways:

  • Macros generate Lisp code.
  • They are evaluated during macro expansion time - before "regular" code is evaluated.

For example:

; A simple macro that generates code to square things
(defmacro square (x)
  `(* ,x ,x))

The ` is shorthand for the list function. The , (comma) unquotes an expression (in this case the argument x). Therefore, the following use of the square macro:

(square 3)

results in this generated code,

(* 3 3)

that Lisp evaluates to produce a useful result.

Lisp cycles

Recursion, eval and macros are just three fascinating aspects of Lisp. Happily, there are many great resources about Lisp (including classic texts in computing) if you want to find out more. If you want to learn online, why not try casting SPELs in Lisp or the Vivid Schemer..?

1 This section is based upon Paul Graham's article, The Roots of Lisp that is itself derived from John McCarthy's original 1960 paper on Lisp, Recursive Functions of Symbolic Expressions and their Computation by Machine. ⇪ Return to article.

1498 words (not including code examples or footnotes). Image credits: The public domain Lisp Alien logo was created by Conrad Barski, M.D.. Lisp Cycles and Lisp Enlightenment cartoons © Randall Munroe under a Creative Commons license.