2 ms·
Paul Graham has a peculiar Lisp style which is NOT mainstream. He is succinct, clever, and usually performance-agnostic. He writes expository code like we write
by mahmud 17y ago
Paul Graham has a peculiar Lisp style which is NOT mainstream. He is succinct, clever, and usually performance-agnostic. He writes expository code like we write one-liners in the repl to quickly test something out.
That example you linked to is confusing because: 1) You don't know the syntax to read it out like a formula, and 2) he uses the names prod and probs which look the same and strain the mind of a newbie.
The way you read "hard" Lisp code, specially one in Graham's style is to read from the last line upwards. The tell-tale is the deep indentation, btw.
Start at the last line, which is the body of MAPCAR, you know mapcar is MAP which applies its first argument function to successive elements of its second-argument, which should be a list.
(mapcar #'(lambda (x)
(- 1 x)) probs)
Make a mental note about the free variable, probs. You can recognize the function as the usual arithmetic step of converting integers to probability values between 0 and 1. The sharp-quote, #', is an archaic style and unnecessary, so let's wrap up these two lines into a function and change the names to be readable.
(defun normalize-probabilities (probabilities)
(mapcar (lambda (x)
(- 1 x)) probabilities))
Ok.
Look up further and notice the result of this function call, a list, is being reduced to an integer. APPLY applies its first argument, a function, to its second argument, a list. For example, (apply #'+ (list 1 2 3 4)) means sum of the first four digits. C programmers should find this familiar: (apply #'main argv)
Where MAPCAR returns a list, apply returns whatever its function argument is supposed to return. We know the function #'* takes a list of numbers and returns their product. So, the snippet is just multiplying the list of probabilities, or reducing to a scalar.
(apply #'* (normalize-probabilities probs))
Then:
(+ prod (apply #'* (normalize-probabilities probs)))
And here something called prod is being added to our scalar. Hmmm.
Look up a bit and see where that's coming from. The nearest binding form for prod is in the LET body on top. Looks very similar to something we have seen before. Another application of multiplication to the list named probs. This is not a Lisp issue, it's a Bayesian statistics or perhaps a PG issues. You continue reading the paper and discover his formula in English prose. Aha! :-)
You can move code around, tuck it into functions and do whatever you want with it. See if you recognize the code snippet now:
(defun normalize-probabilities (probabilities)
(mapcar (lambda (x)
(- 1 x)) probabilities))
(defun pg-foo-fomula (product)
(/ product (+ product
(apply #'* (normalize-probabilities probs)))))
(defun main ()
(loop
(let ((probabilities (eval (read))))
(when (listp probabilities)
(print (pg-foo-formula (apply #'* probabilities))))
(princ "OK > "))))
Typically you don't do that; you don't make silly repls and you never ever write a MAIN or any other program entry function. You write libraries, that you use in other libraries, and you orchestrate them all via interactive use and deploy in a custom image.
- m0th87 17y agoYou should write a book on practical lisp. I'd buy it!