Thursday, September 16, 2010

Steve Yegge: How many primitives does it take to build a LISP machine?

In one of Steve Yegge's awesome essays he says:

Its part of the purity of the idea of LISP: you only need the seven (or is 
it five?) primitives to build the full machine.

So how many primitives do you need? What primitives don't you need? How do we define 'the full machine'? And How do we prove it? Let's go find out. This is going to be fun. 

Assumptions:
For this exercise we'll be working in Common LISP. 

How Many Primitives Do you Need?
How many have you got? This site reckons there are in fact ten. These being
atom, quote, eq, car, cdr, cons, cond, lambda, label, apply

So if Steve reckons we can do it in seven, some of these primitives are going to drop off the essentials list. 

What Primitives Don't You Need?
We don't want to give the game away just yet, but it looks like Paul Graham reckons that McCarthy reckons that apply is the one that drops off. 

How Do We Define 'The Full Machine'?
This is really the crux of the question. (You may even get different answers depending on how you define this.) For this question we'll say that 'the full machine' is a LISP eval function - and we'll use Paul Graham's interpretation of McCarthy's eval function for this. 

How do we Prove it?
We write an eval function - and count the primitives it implements. 

(defun null. (x)
      (eq x '()))

(defun and. (x y)
  (cond (x (cond (y 't) ('t '())))
        ('t '())))

(defun not. (x)
  (cond (x '())
        ('t 't)))

(defun append. (x y)
  (cond ((null. x) y)
        ('t (cons (car x) (append. (cdr x) y)))))

(defun list. (x y)
  (cons x (cons y '())))

(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))))))

(defun assoc. (x y)
  (cond ((eq (caar y) x) (cadar y))
        ('t (assoc. x (cdr y)))))

(defun eval. (e a)
  (cond
    ((atom e) (assoc. e a))
    ((atom (car e))
     (cond
       ((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))
                  a))))
    ((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)))))

(defun evcon. (c a)
  (cond ((eval. (caar c) a)
         (eval. (cadar c) a))
        ('t (evcon. (cdr c) a))))

(defun evlis. (m a)
  (cond ((null. m) '())
        ('t (cons (eval.  (car m) a)
                  (evlis. (cdr m) a)))))


(eval '(car '(a a)) )
What's the Answer?
We've already given it away - but it is looking like 9 for Common LISP. 

Are there any bugs in this?
Interestingly enough - this guy @DomQ reckons he emailed Paul Graham with notice of a bug in the code of his original article. Paul Graham's response was that it was actually a bug in McCarthy's code - but that McCarthy wasn't interested in that kind of error handling. You can see a fix for the bug here

Could this be improved?
To be truly LISP - you need an eval function that can eval itself. (Something for another day.)

Bibliography:

Saturday, July 17, 2010

What is the 100 days of the Little Lisper?

The Little Lisper is an incredible book for a number of reasons:

  • It frees your mind from the constraints of an algol-style language such as C# or Java and changes your hammer-based approach to algorithmic problem solving to that of a lever 
  • It has a breezy question and answer style that helps you work through big concepts in an easy and approachable way
  • It's bottom-up, axiomatic approach shows how you can build up a whole language from a few simple primitives
  • Understanding the y-combinator will blow your mind
  • It's style is rich in examples of food, avoiding the dryness of other programming books

So Why the 100 Days of the Little Lisper?
The ideas in LISP are timeless and have influenced many modern languages. The latest incarnation of this has been the addition of lambda expressions to C#, and its proposed introduction in Java 7. 

But these are but shadows of the original. To really understand how these ideas hang together, it is essential to go back to the beginning and understand the roots of all these ideas. 

The 100 days of the Little LISPer celebrates these ideas by providing a new solution to a problem in the book each day - for each of the 100 in the book. It aims to respect the Copyright of the original book by providing no more than what is already available online - so it is much better if you buy the original. 

Why LISP?
Any other reason to read the book? It gets you started in LISP which has lead to the following:
  • LISP's emphasis on homoiconic languages have big pay-offs when it comes to writing macros as evidenced by Paul Graham in Beating the Averages
  • LISP's paradigms have influenced the development of massive computing clusters at Google, where the MapReduce model is inspired by two LISP functions, map and reduce
  • Eric Raymond's comment that, "Lisp is worth learning for the profound enlightenment experience you will have when you finally get it; that experience will make you a better programmer for the rest of your days, even if you never actually use Lisp itself a lot."


Saturday, June 12, 2010

The Little LISPer - Chapter 10 - What is the value of all this?

You can go to the parent page here.



These are links to worked examples of The Little Lisper (3rd Edn.) in Common Lisp. They are being released in sequence, so not all are available now.



The assumption is that you have a copy or have read Mattias Felleison's The Little LISPer. (http://www.amazon.com/dp/0023397632/).



The questions are also available here (http://www.ccs.neu.edu/home/matthias/BTLS/exercises.ps)


Exercise 1: YourDSL - Can you evaluate this S-expr?
Exercise 2: YourDSL - Can you evaluate this lazy S-expr?
Exercise 3: YourDSL - Will your eval produce closures?
Exercise 4: YourDSL - How to rewrite your function
Exercise 5: YourDSL - How to rewrite closures and primitives
Exercise 6: YourDSL - Can you represent a table as a fn?
Exercise 7: YourDSL - Is this S-Expr a lambda-expression?
Exercise 8: Can you change a function-table to a function?
Exercise 9: YourDSL - building  fns by eval'ing an expr
Exercise 10: Can you completely rewrite lisp in your DSL?

The Little LISPer - Chapter 9 - Lamdba The Ultimate

You can go to the parent page here.



These are links to worked examples of The Little Lisper (3rd Edn.) in Common Lisp. They are being released in sequence, so not all are available now.



The assumption is that you have a copy or have read Mattias Felleison's The Little LISPer. (http://www.amazon.com/dp/0023397632/).



The questions are also available here (http://www.ccs.neu.edu/home/matthias/BTLS/exercises.ps)
Exercise 1 - Can you rewrite your function to map it to a list?
Exercise 2 - ycombinator - Apply this fn to this pair in the list
Exercise 3 - Can you rewrite your function for the ycombinator?
Exercise 4 - Rewrite member for the ycombinator
Exercise 5 - Use a continuation function instead of an evaluator
Exercise 6 - Can you abstract these two functions into an accumulator?
Exercise 7 - Can you abstract accumulators into a single function?
Exercise 8 - Can you write your function as a thunk?
Exercise 9 - Can you combine an S-expr and a thunk to make a stream?
Exercise 10 - Can you use P and Q to build a stream?

The Little LISPer - Chapter 8 - Friends and Relations

You can go to the parent page here.



These are links to worked examples of The Little Lisper (3rd Edn.) in Common Lisp. They are being released in sequence, so not all are available now.



The assumption is that you have a copy or have read Mattias Felleison's The Little LISPer. (http://www.amazon.com/dp/0023397632/).



The questions are also available here (http://www.ccs.neu.edu/home/matthias/BTLS/exercises.ps)


Exercise 1: Expression evaluators - Is this an identity relation?
Exercise 2: Expression evaluators - Is this reflexive?
Exercise 3: Expression evaluators - Is this symmetric?
Exercise 4: Expression evalutors - What is value of f at x?
Exercise 5: Expression evaluators - Compose function f and g?
Exercise 6: Expression evalutors - Can you evaluate this relation?
Exercise 7: Expression evals - Is your relation of pairs prepped?
Exercise 8: Expression evals - Can you compose these relations?
Exercise 9: Expression evaluators - Is your expression transitive?
Exercise 10: Expression evals - Is your expression partial order?

The Little LISPer - Chapter 7 - Shadows

You can go to the parent page here.

These are links to worked examples of The Little Lisper (3rd Edn.) in Common Lisp. They are being released in sequence, so not all are available now.

The assumption is that you have a copy or have read Mattias Felleison's The Little LISPer. (http://www.amazon.com/dp/0023397632/).

The questions are also available here (http://www.ccs.neu.edu/home/matthias/BTLS/exercises.ps)


Exercise 1: Starting writing your own arithmetic DSL in Lisp
Exercise 2: Validating an expression in your DSL
Exercise 3: Count the operators in your DSL
Exercise 4: Count the operands in your DSL
Exercise 5: Make your DSL expressions scalable
Exercise 6: Add binary operators to your expressions
Exercise 7: In your DSL check you have values for your expressions
Exercise 8: Get the variables passed into your expression DSL
Exercise 9: Evaluate your expression in your DSL
Exercise 10: Add binary operators into the evaluation of your DSL

The Little LISPer - Chapter 6 - *Oh my Gawd*: It's Full of Stars

You can go to the parent page here.

These are links to worked examples of The Little Lisper (3rd Edn.) in Common Lisp. They are being released in sequence, so not all are available now.

The assumption is that you have a copy or have read Mattias Felleison's The Little LISPer. (http://www.amazon.com/dp/0023397632/).

The questions are also available here (http://www.ccs.neu.edu/home/matthias/BTLS/exercises.ps)



Exercise 1: Finding the hidden chili and separating them out
Exercise 2: Is there chili in the hot potatoes? (nested intersection)
Exercise 3: Double frying the baked tomatoes (nested atom duplication)
Exercise 4: LISP asking three questions about the fried potatoes
Exercise 5: Fish and chips - finding the first nested occurrence
Exercise 6: Adding the nested numbers
Exercise 7: What does this function g* do?
Exercise 8: What does this function f* do?
Exercise 9: Can we accumulate the potatoes in this dish?
Exercise 10: Can we accumulate the (nested) potatoes in this dish?