Notes on Lisp

by moodyharsh

(define (eval exp env)
(cond ((self-evaluating? exp) exp)
((variable? exp) (lookup-variable-value exp env))
((quoted? exp) (text-of-quotation exp))
((assignment? exp) (eval-assignment exp env))
((definition? exp) (eval-definition exp env))
((if? exp) (eval-if exp env))
((lambda? exp)
(make-procedure (lambda-parameters exp)
(lambda-body exp)
((begin? exp)
(eval-sequence (begin-actions exp) env))
((cond? exp) (eval (cond->if exp) env))
((application? exp)
(apply (eval (operator exp) env)
(list-of-values (operands exp) env)))
(error “Unknown expression type - EVAL” exp))))

Lisp treats everything as a linked-list of symbols both internally and visually. Some symbols are
compiled in as primitives.

This format is lowlevel enough for implementing assembly code and high level as well for multi-paradigm programming.
Lisp innovations

  1. If
  2. Garbage Collection
  3. Closures
  4. Macros
  5. Symbols
  6. Generic Functions
  7. Code Generation
  8. Declarative Programming (DSL)
  9. REPL
  10. Continuations
  11. Application Scripting

List -> (Atoms | Lists)
Atom -> Symbol | String | Number | Array | Dictionary | Lambda
Lambda -> List
File -> Lists

lisp’s core operators -> cond, quote, lambda, datatypes, arithmetic, logic operators.

the power of lisp arises because it treats everything as a list of symbols.
the reader coverts the syntax into list of symbols.
the evaluater will evaluate this list based syntax of associated to symbols and will give value to the parent.
whenever the reader sees a macro eval will list of argument symbols to the macro function to do list transformations.

(setf x exp)
(if exp exp1 exp2)
(cond (exp1 exp2)
(exp3 exp4))
(case symbol
(exp1 exp2)
(exp3 exp4))

(loop for i from 1 to 10
across list
symbol = exp
with symbol = exp
always exp
never exp
when exp
if exp
else exp
do exp
collect exp

(do* (list1
(exp exp))

(block name (exp1 exp2))
(return-from name (exp)) – valid in functions
(return exp) – valid only in do*,loop,prog*

(tagbody name1 (exp1 exp2)
name2 (exp1 exp2))
(go name)

(prog* (list1 list2) (label1 exp1 exp2 label2 exp3 exp4))
(go label)
(return exp)

(progn exp1 exp2)

(defun symbol list exp1 exp2)
(demacro symbol list exp1 exp2)
(let* (list1
exp1 exp2)

exp == (symbol exp1 exp2) or (progn exp1 exp2)
list == (list exp1 exp2)

A majority of usecases for macros, which don’t require code transformation can be simulated using closures because both
rely on suppression of code execution. It is better to think of macros as code templates.

This is what parens style indentation look like in C

int main(void)
    {int i};

    for (i=1); i<=100; i++)
       {if (i%15 == 0
            {printf ("FizzBuzz\t")});}
        else if ((i%3) == 0)
        else if ((i%5) == 0)
            {printf("%d\t", i)}};}}

    return 0;}

I personally disagree with this style and I prefer to use parens on their own lines.
I also think lisp should support better text macros and function call syntax.

Lisp is unpopular because it forces functional programming instead of providing clean imperative constructs.
Bad docs.
Bad libraries.

A majority of lisp programmers come to it via emacs or sicp.

A new trend in lisp implmenentations it to implement it over a host language,
like clojure, hylang, liskell, lfe. Lisp is unpopular because it is difficult to read.