 The first thing we need to know about reading and writing closure is the unique way LISP source code gets compiled or interpreted. If you've ever worked with complex data in text form, you'll know that it's always best to first convert the text data into an object representation because it's simply easier and less error prone to work with it in that form. This is why compilers and interpreters first convert source code into what's called an AST, an abstract syntax tree, and object representation of the source. What a typical abstract syntax tree looks like is that, say, the text that makes up a function is represented as a function object, and that function object contains statement objects, which are themselves in turn made up of expression objects. In LISP dialects, the part of the compiler or interpreter which translates the source code to objects is called the reader, and the object form of LISP source code is not normally called an AST, but rather simply called reader data. What's different about reader data is that whereas an AST represents language constructs like statements and functions, reader data is composed of standard LISP data types, like numbers, strings, and lists, the ordinary stuff that we use in our own LISP code. Just like JSON data is a hierarchy of arrays and objects nested within arrays and objects, LISP reader data is composed of lists and maps nested within lists and maps. The part of a LISP compiler which actually generates running code is called the evaluator. The evaluator converts reader data into running code using a fairly simple set of rules. So whereas the workings of a traditional compiler or interpreter are usually a black box unknown to you, the programmer, in LISP the workings are quite transparent. Effectively, learning how the reader and evaluator process LISP code is the same as learning how to read and write LISP. So first let's look at exactly how Clojure's reader reads Clojure code. First, strings and Clojure are one and the same with Java strings. A Clojure string is a Java string, and they are written the same way. Inside double quote marks, never single quotes. When you use single quotes around a single character, that denotes a Java character, not a string. Integers in Clojure that fit in Java's long range are Java longs. Otherwise, integers are instances of a type defined by Clojure called closure.lang.bigint. Floating point values are by default Java doubles, but a number suffixed with a capital M is a Java big decimal. We'll discuss how the various math operations handle these different number types later. In the meantime, you can mostly ignore these differences and just treat numbers like numbers. Clojure nil is exactly equivalent to Java null. The name nil is used simply because it is traditional in LISP. Identifiers in LISP are called symbols, and they are treated themselves as a kind of value. Think of symbols as like a distinct type of string that isn't surrounded in double quote marks and which may not contain certain characters, such as white space characters. A symbol enclosure may be composed of letters of the alphabet and the punctuation marks dot asterisk plus sign exclamation mark less than greater than hyphen underscore question mark and apostrophe, except apostrophe cannot be the first character of the symbol. A symbol may also contain numerals but may not begin with a numeral, and a symbol may also contain a single forward slash, but not as the first or last character. What closure calls a key word is just like a symbol, but it begins with a colon. Keywords exist in the language mainly because we sometimes want something that's just like a symbol, which is yet distinct from a symbol. Lastly, closure has three basic types of collections lists vectors and maps, all of which are persistent lists are denoted by parentheses vectors by square brackets, and maps by curly braces. Closure treats commas like white space. So you can add commas between the elements if you prefer, but commas are never required. A closure list is an ordered collection implemented as a singly linked list. Each element is a node with a value and a link to the next element node. Because of this structure lists are not well suited for random access of the elements. Vectors are also ordered collections, but a vectors elements are stored as a tree of nodes. As we'll discuss in some detail later, this tree structure allows for relatively efficient random access to the elements, while also enabling the vector to be fully persistent. Lastly, maps are unordered collections of key value pairs. This map here has two key value pairs, the key string foo with a value three, and the key five with a value seven. Notice that the keys and values are only distinguished by the keys coming before the values. The keys of maps are most commonly strings numbers and keywords, but a key may be any immutable object, even a list vector or map. This actually covers nearly all of closure syntax. There are a few special characters will introduce later, but they mostly represent conveniences. Consider now this small example of closure code. We haven't yet explained how closure data gets translated into running code, but you should be able to parse the reader data. What the reader sees here is a list containing four elements, the symbol def n, the symbol hello world, an empty vector, and another list containing the symbol print, followed by the string hello world. Because closure syntax is free form, we can indent code as we like, but we generally indent the start of nested parentheses. Here I've added end of line comments with the semicolon character, a semicolon and everything after it on the same line is ignored by the reader. Before we can understand how the evaluator processes reader data, we first must understand two more closure data types, vars and namespaces. A var short for variable simply holds a mutable reference to another object. A namespace is a special kind of map in which the keys are symbols, and the values are vars. Unlike the other collections, a namespace is mutable, so its key value pairs may change over the course of a program. Each namespace in a closure program is known by a unique symbol name. So the namespaces themselves are effectively organized into a global namespace. A program's namespaces may look something like this. Here we have two namespaces cat and dog. The cat namespace contains just one symbol mittens mapped to a var, and the dog namespace contains three symbols, spot, rover and spike, each mapped to vars. So be clear about the chain of look ups. Each namespace is known by a symbol name, each namespace mapped symbols to vars, and each var itself holds a mutable reference to some other object. The standard library namespace closure.core contains nearly 500 functions, including the functions for basic operations like arithmetic. For example, the addition function is stored in a var mapped to the symbol plus sign in the closure.core namespace. Remember that plus sign is a valid closure symbol character. It may seem strange for such functionality to be implemented as functions instead of built in operators, but it's consistent with keeping the core of the language extremely simple. You might object that basic operations shouldn't incur function call overhead, but the Java virtual machine is actually extremely good at aggressively inlining functions. And so most of the time, the function call overhead gets optimized away. Now that we've introduced namespaces vars and a few standard functions, we can talk about how the evaluator works.