The Toups Theory of Programmer Perverseness:
Some sublunar programming constructs persist because their awfulness makes programmers feel clever.This is the animating force behind obfuscated code contests and esoteric programming languages. This is also the impulse behind secret societies, gnosticism, cults. We love having esoteric, secret knowledge or hard to acquire abilities. Hence the success of absolutely shockingly bad ideas, like Perl or C++ template metaprogramming. I think this also might explain the lock of popularity of Lisp and Smalltalk (and don't forget Forth), to a certain extent. All of these languages are exceedingly simple, conceptually, and have almost no syntax. I've had friends complain about this very aspect of the languages - claiming that humans prefer a bit more visual structure to sink their teeth into. Maybe it is just that sequences of tokens just don't look that cool. A friend of mine always complained about the Apple design philosophy: minimize edges, make smooth contours, that kind of thing1. She claimed to prefer the taupe boxes of her bucolic youth - machines which looked like machines. Hell, even Steampunk might reflect this urge for complex things to look complex, perhaps more than they need to. So despite the arguably oppressive simplicity of Lisp, it is still possible to write some ridiculous looking code. A commonly mentioned example of this kind of thing is folding. For those not into this sort of thing, fold (really fold left) is kind of the fundamental functional representation of iteration. Fold takes a function of two arguments, the first of which is some notion of the "current value" and the second of which is in some sense an "accumulator". In addition, it takes an initial value and a list of items to work on. An example will be illustrative with a bit of thought:
(foldl (lambda (it ac) (+ it ac)) 0 '(1 2 3)) -> 0+1+2+3 = 6(not 5, thanks Anonymous) Fold is sort of nice from one perspective - it is very abstract. All of the "noise" of iteration is hidden in a relatively elegant way. The real work is writing a function of the current value and the accumulator. It feels a little like thinking of the derivative of the loop rather than the loop itself, once you get used to it. On the other hand, Guido Van Rossom once wrote, rather famously (N.B. reduce in Python is foldl in Scheme):
So now reduce(). This is actually the one I've always hated most, because, apart from a few examples involving + or *, almost every time I see a reduce() call with a non-trivial function argument, I need to grab pen and paper to diagram what's actually being fed into that function before I understand what the reduce() is supposed to do. So in my mind, the applicability of reduce() is pretty much limited to associative operators, and in all other cases it's better to write out the accumulation loop explicitly.I've always felt this was a little too simple minded, as Python is arguably wont to be. But when I started really writing a lot of scheme code, I made myself write with folds rather than named lets or loop macros, just to see what it is like. I have to admit, it takes some getting used to, and is perhaps not always the clearest way to express iteration. For instance, I have some code to multiply two polynomials in PLT Scheme:
Which I admit is not all that easily understood. What is interesting about this to me, is that often code is hard to understand because the level of abstraction is too low. In this particular case, the level of abstraction is too high - or at least it is somehow "sideways" from the problem we are trying to solve. Or maybe it isn't? Maybe a syntactic abstraction is higher than a functional one? I'd love to hear how people felt about folding vs looping. 1: Apple Design Philosophy in One Sentence: figure out the rough dimensions the product must have to house the underlying technology and then ask "If I had to put this in my ass, what would I want it it look like?"
(define (mult-polynomials p1 p2) (let ((terms1 (map list (reverse (coefs p1)) (range-list 0 (order p1)))) (terms2 (map list (reverse (coefs p2)) (range-list 0 (order p2))))) (foldl add-polynomials (polynomial! 0) (foldl (fn (term1 polys) (foldl (fn (term2 inner-polys) (cons (mult-poly-terms (car term1) (cadr term1) (car term2) (cadr term2)) inner-polys)) polys terms2)) '() terms1))))