Programming Languages

Lisp Philosophy

Jim Posen - ECE/CS 2014

History of Lisp

  • 1955 - John Backus invents Fortran at IBM
  • 1958 - John McCarthy invents Lisp at MIT
  • 1958 - First interpreter is written
  • 1962 - First compiler is written
  • 1972 - C is released
  • 1975 - Scheme
  • 1984 - Common Lisp
  • 2007 - Clojure

Applications

  • Lisp is big in AI
  • Lisp often used to create DSLs
  • Fragmented ecosystem + limited libraries = limited usage

Mathematical foundation

  • Assembly/Fortran based on Turing machine formalism
  • Lisp based on Lambda Calculus

Lambda Calculus

  • Invented in 1930 by Alonzo Church
  • Mathematical formalism for functions and function application
  • Variables and anonymous functions are called “lambda terms”
  • Introduces notion of a function as a first class variable
  • Lambda functions have one input and one output

Functional Programming

  • What is it and why is it different?
  • Lisp is the first functional programming language
  • Modern lisps are not purely functional
  • Rather, Lisp encourages a functional style of programming

Functions

  • Functions have inputs, outputs, side effects, and an environment
  • Inputs are your function parameters
  • Outputs are your return values
  • Side effects are everything else

An example

  • Collatz sequence
    • n -> n/2 (n even)
    • n -> 3n + 1 (n odd)
    • 13 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1
  • Collatz conjecture is that all sequences end in a 1

What are the inputs, outputs, and side effects of collatz ?

(define (collatz-next n)
  (if (even? n)
      (/ n 2)
      (+ 1 (* 3 n))))

(define (collatz n)
  (displayln n)
  (cond
    ((= n 1) 1)
    (else (+ 1 (collatz-next n)))))
  • Input is the starting number
  • Output is the length of the sequence
  • Side effect is printing to the screen every element
  • Environment includes the definition of collatz-next

Functional programming benefits

  • Sides effects often include changing state of the environment
  • Setter methods have side effects
  • Side effects add lots of complexity
  • Side effects can be hard to debug

Alternately…

  • Functions with no side effects can be easily tested
  • Functions with no side effects are less likely to cause weird bugs
  • Functional programming makes your code more modular and easier to understand

Other Lisp goodies

  • The following features didn’t exist before Lisp
  • Conditionals instead of goto statements
  • First class functions
  • Recursion paradigm
  • Garbage collection
  • Program as a tree of S-expressions
  • REPL

The Roots of Lisp

7 primitive operators

  • quote
  • atom (check if atom or null)
  • eq (equality of atoms)
  • car
  • cdr
  • cons
  • cond

Functions

  • Functions are lambdas
  • May be given labels for the purpose of recursion

The Surprise

  • Paul Graham’s self hosting 32 line Lisp interpreter
  • Pretty sweet, huh?

Advanced features of Lisp

  • Lexical closures
  • Macros

Variable scope

  • A scope is the context in which variables may be defined
  • Defines, lambdas, and let blocks create new scope in Racket
  • Variables defined in a scope are not accessible outside it

Lexical closure

  • A closure is a function along with it’s referencing environment
  • Racket and modern Lisps support closures
  • This mean a function can refer to variables in a local scope when called outside that scope

What does this mean?

Function “remembers” out of scope variables

(define (makefilter op x)
  (lambda (n) (op x n)))
(let ((my-filter (makefilter < 8)))
  ... (my-filter 6) ...)

Why are closures good?

Let’s simplify our quicksort code

Before

(define (qsort lst)
  (cond
   ((null? lst) '())
   (else
    (let* ((pivot (car lst))
           (less-than? (lambda (x) (<= x pivot)))
           (greater-than? (lambda (x) (> x pivot))))
      (append
       (qsort (filter less-than? (cdr lst)))
       (list pivot)
       (qsort (filter greater-than? (cdr lst))))))))

After

(define (qsort lst)
  (cond
   ((null? lst) '())
   (else
    (let ((pivot (car lst)))
      (append
       (qsort (filter (makefilter <= pivot) (cdr lst)))
       (list pivot)
       (qsort (filter (makefilter > pivot) (cdr lst))))))))

Custom syntax

  • Functions are cool, but we can’t really add syntax
  • Can we write a for loop?

The for loop

How can we implement this?

(for i '(1 2 3 4)
  (* i 2))
=> '(2 4 6 8)

Not with a function…

The loop functionality

We can achieve the same result with

(map (lambda (i) (* i 2)) '(1 2 3 4))

But I liked the for loop syntax

Can we just expand the for loop into that?

Macros

The interpreter replaces your macros with another expression defined by a syntax rule

(define-syntax-rule (for var lst body)
  (map (lambda (var) body) lst))

Another example

(define-syntax-rule (swap x y)
  (let ([tmp x])
    (set! x y)
    (set! y tmp)))
(swap first second)

Why can we do this?

Because

Beating the Averages

  • Lisp is a programmable programming language
  • You can write programs to write your programs for you
  • Customize the language to your needs with custom syntax
  • This is why Lisp is so good for writing DSLs

Wrapping up

  • Complete all exercises
  • Run all tests
  • Email me (jep AT duke DOT edu) if you have questions
  • Push code to your GitHub repository

Next time on Programming Languages

  • Haskell
  • Purely functional programming
  • Typing models