## 2019-03-11 Learning Lisp

**Atomic Symbol**: Basically an alphanumeric identifier
- starting with a letter
- only includes upper-case letters
- cannot be split further

*Just using plain JavaScript identifier/strings for this.*

```javascript
start(1, 'foo')
```
<script>
3+4
</script>

**S-Expressions**: either an atomic symbol or: '(', s-expression, '.', s-expression, ')'.

<script>
class ConsCell {
  constructor(l, r) {
    this.l = l
    this.r = r
  }
  
  toString() {
    return `(${this.l}, ${this.r})`
  }
}
</script>

### function names
are lower case letters, arguments in square brackets, separated by semicolon.

We will use normal functions to represent them:

#### cons

```javascript
cons[A;B] --> cons(A, B)
```

<script>
function cons(l, r) {
  return new ConsCell(l, r);
}

cons(cons('A', 'B'), 'C')
</script>

#### car
<script>
function car(arg) {
  if (atom(arg) === 'F') {
    return arg.l;
  } else {
    throw 'car of atomic symbol is undefined'
  }
}

car(cons(cons('A', 'B'), 'C'))
</script>

#### cdr
<script>
function cdr(arg) {
  if (atom(arg) === 'F') {
    return arg.r;
  } else {
    throw 'cdr of atomic symbol is undefined'
  }
}

cdr(cons(cons('A', 'B'), 'C'))
</script>

#### predicate *eq*

true and false normally represented as **T** and **F**. We use JavaScripts `true` and `false` here.

*eq* tests equality of atomic symbol, undefined otherwise.

<script>
function eq(a, b) {
  if(atom(a) === 'T' && atom(b) === 'T') {
    return a === b ? 'T' : 'F'
  } else {
    throw `eq of non-atomic symbols ${a} and ${b} is undefined`
  }
}

eq(cons(1,2), 'A')
</script>

#### predicate *atom*

<script>
function atom(x) {
  if (x instanceof ConsCell) {
    return 'F'
  } else {
    return 'T'
  }
}
atom(cons('A', 'B'))
</script>

#### list notation

```lisp
(A B C D E) --> (A . (B . (C . (D . E))))
```

We use the helper **l** for this. **NIL** is the empty list.

<script>
function l(...args) {
  if (args.length == 0) {
    return 'NIL';
  }
  return cons(args[0], l(...args.slice(1)))
}
l('A', 'B', 'C', 'D', 'E');
</script>

#### cadr, cdar, cadadr, ...

convenience for chaining those operators:

<script>
function caar(arg) { return car(car(arg)) }
function cadr(arg) { return car(cdr(arg)) }
function cdar(arg) { return cdr(car(arg)) }
function cddr(arg) { return cdr(cdr(arg)) }

function caaar(arg) { return car(car(car(arg))) }
function cadar(arg) { return car(cdr(car(arg))) }
function cdaar(arg) { return cdr(car(car(arg))) }
function cddar(arg) { return cdr(cdr(car(arg))) }
function caadr(arg) { return car(car(cdr(arg))) }
function caddr(arg) { return car(cdr(cdr(arg))) }
function cdadr(arg) { return cdr(car(cdr(arg))) }
function cdddr(arg) { return cdr(cdr(cdr(arg))) }

function caaaar(arg) { return car(car(car(car(arg)))) }
function cadaar(arg) { return car(cdr(car(car(arg)))) }
function cdaaar(arg) { return cdr(car(car(car(arg)))) }
function cddaar(arg) { return cdr(cdr(car(car(arg)))) }
function caadar(arg) { return car(car(cdr(car(arg)))) }
function caddar(arg) { return car(cdr(cdr(car(arg)))) }
function cdadar(arg) { return cdr(car(cdr(car(arg)))) }
function cdddar(arg) { return cdr(cdr(cdr(car(arg)))) }
function caaadr(arg) { return car(car(car(cdr(arg)))) }
function cadadr(arg) { return car(cdr(car(cdr(arg)))) }
function cdaadr(arg) { return cdr(car(car(cdr(arg)))) }
function cddadr(arg) { return cdr(cdr(car(cdr(arg)))) }
function caaddr(arg) { return car(car(cdr(cdr(arg)))) }
function cadddr(arg) { return car(cdr(cdr(cdr(arg)))) }
function cdaddr(arg) { return cdr(car(cdr(cdr(arg)))) }
function cddddr(arg) { return cdr(cdr(cdr(cdr(arg)))) }

cadadr(l('A', l('B', 'C'), 'D'));
</script>

### Lisp Meta language

<script>
function c(...cases) {
  for (let [expr, then] of cases) {
    if(expr === 'T') {
      return then;
    }
  }
}

c(
[eq('A', 'B'), l('FIRST')],
[eq(cdr(cons('A', 'B')), 'B'), l('SECOND')],
['T', l('DEFAULT')]
)
</script>

#### Lambda and Label

- lambda defines an anonymous function

<script>
function lambda(fn) {
  return fn
}
</script>

- label binds a function to a name

<script>
function label(unique_identifier, fn) {
  return window[unique_identifier] = fn
}
label('my_fn', lambda((x) => cons(x, x)))
my_fn(l('A', 'B'))
</script>


---

## Stuff

```javascript

```

<script>

</script>
