>>85
I don't think LISP or C would be called “deficient”.
It's a matter of how easily you can put your computations in them, which is closely related to the way you design your programs, and the objectives you may need to meet.
Like the factorial program from before, the mathematical definition is clearly a recursion. Both languages have ways to clearly represent this problem. But it's when machine/implementation issues come to haunt our clean and concise programs.
You need to optimize, even if you don't need, but you'll want because it's cool enough. Then you have two ways: iteration and tail-recursion. Let's take a look at code (forgetting about fact(n) for n <= 0):
int fact(int n) {
int c;
for (c = n-1; c > 0; c--)
n *= c;
return n;
}
(define fact
(λ (n r)
(if (= n 0) r
(fact (- n 1) (* r n)))))
(define factorial
(λ (n) (fact n 1)))
Both forms give a
good layer of abstraction over actual hardware instructions, but they still make you warned about machine stack limit. With LISP, it stops here. But with C, the abstraction level is more closely tied to hardware details, and you can see int types and increments, things really not strictly necessary to our problem.
Anyone could say this is a “braindead simple” example, but most real code are. The problem is just that such trivial code is often overlooked, and a simple overflow or wrong conversion can have dangerous consequences (in memory of Apollo 1 crew), because the language put these nasty details in your hands.
You talked about “human readability” but in fact what C does is showing you more machine stuff. I really think you know a lot about machine instructions, caching, memory access and stuff, so it's clearly obvious that you know how things should work if you need the maximum speed. Because you know this all, every optimization trick you do seems natural and easy, and you'll start to bend your designs to specific decisions. This is what
I call
premature optimization.
But really, I don't care about
#include <void.h> neither
(define x ((let ((...))))))))))). What I really care is about how difficult or spending is to understand what someone's code does. No matter if it's written in LISP, Python, C++ or whatever. But there's some stuff that seems to help me when I'm studying
algorithms, or deducing them while reading some implementation:
- meaningful but short names;
- proper spacing (implying indentation is a must, and FIOC is better than one-line programs);
- more comments = less readable code;
- analogies with common knowledge.
And none of them is about objects, first class functions, templates, garbage collection and shit. They're cool features but that's all, they will not explain what is your program going to do
!
Enough boredom, I'll get back to work and become a better programmer.