There's a video making the rounds about how hard it is to re-learn how to ride a bicycle if you reverse the control sense of the handlebars. It's an interesting video, but I think it misses a very important point.
I need to digress for a disclaimer: I have not had the opportunity to ride a reverse-handlebar bicycle, so I have not put the theory I am going to advance here to the test. If anyone knows where I can find such a bike in the Bay Area I would really welcome the opportunity.
The reason people have a hard time learning to ride a bicycle for the first time is that they think that the direction of the bicycle is controlled by turning the handlebars the way that the direction of a car is controlled by turning the steering wheel. It's not. The mechanics of two-wheel vehicles are completely different from four-wheel (or even three-wheel) vehicles. A bicycle's direction is controlled not by turning the handlebars, but by shifting your weight.
There's a simple experiment you can do on an ordinary bicycle to convince yourself that at least part of what I have just said is true: find a moderately sloped hill that lets you coast at a moderate speed (10-15 MPH) without pedaling. Stabilize your trajectory in a more or less straight line. Now let go of one handlebar, so you are "steering" with only one hand. Use that hand to push that handlebar forward. Don't do it abruptly, just apply gentle, even pressure. If you're using your right hand, you will be turning (at least feel like you're trying to turn) your front wheel to the left. What you will find is that your bike will actually turn to the right. If you want to turn back to the left, you have to pull back with your right hand as if you were turning your front wheel to the right. (I say "as if" because you will find that the front wheel actually does turn to the left despite the fact that you are applying pressure to turn it to the right!)
All this only works if you're going fast enough. When a bike is moving slowly, its direction is controlled more by how you turn the handlebars than how you lean. The hardest part of learning to ride a bicycle is learning to manage the transition between these two control regimes. This is the reason that training wheels are worse than useless when learning to ride a bike. They change the bike from a two-wheel vehicle to a four-wheel vehicle, which doesn't undergo this change in dynamics. If you want your kid to learn to ride a bike, take the pedals off instead of using training wheels.
When a bike is traveling at speed, what happens when you apply pressure to the handlebars is this: let's say that you apply forward pressure with your right hand so that the wheel would ordinarily turn to the left. For a fraction of a second, it actually does turn to the left, and the track of your tires moves to the left. But your body is still moving in the same direction it was before, so you have essentially shifted your weight to the right. So at the moment, you are out of balance.
What happens next is a little tricky to describe. Notice that the head tube (the part of the frame that the front fork is attached to, is angled so that the bottom of the tube is further forward than the top. The result of this is that when the bike leans in one direction, the weight of the bike and its rider causes the front wheel to turn in the same direction as the lean. It is this force that controls where the front wheel is pointing when the bike is moving at speed.
The reason a bike is stable when it is moving is not the gyroscopic stability of the wheels, it is the angle of the head tube, which causes the front wheel to want to point in the same direction as the bike is leaning. As soon as you start to lean one way or the other, the front wheel naturally turns in the same direction, which moves the wheels back underneath your center of gravity and "undoes" the lean. In order to turn, you have to intentionally overcome the bike's natural stability and induce a lean in order to force the front wheel to turn to one side or the other.
So what happens when you apply pressure to the handlebars at speed is not that you are turning the bike, but you are inducing a lean. You can do exactly the same thing by actually leaning, and it doesn't take much. Once you are stabilized, just moving your head from one side to the other can be enough to cause your bike to turn.
Once you realize this, it is easy to learn to ride without having your hands on the handlebars at all. You slowly release your grip until you just have your fingertips on the handlebar. At this point you will notice that you can control your bike by applying pressure to the sides of the seat of the bike with your inner thighs, or by tilting your head back and forth. It takes just a few minutes to learn how to steer the bike this way, at which point you can just take your hands completely off the handlebars. At that point, of course, it doesn't matter whether the handlebars are reversed or not.
But, of course, all this only works once the bike is moving. The hard part is getting to that point from a standing start.
The key here (and at this point I'm really only guessing) is to remember two things: 1) the object of the game is to get the bike moving as quickly as possible and 2) what you're trying to do during that time is not to steer, but simply to keep the front wheel straight. To do that with a reverse-sense handlebar you do have to change your mindset. My guess is that what would work best is to make a conscious effort to think of the process as a game of "chase the front wheel with the handlebars", i.e. if you see the front wheel turning to the right, you "chase" it by turning the handlebars to the right, and vice versa. The result will be the wheel wobbling back and forth around its forward position, but that should be enough to keep you upright long enough to get up to speed.
My prediction is that someone who has read this blog post can learn how to ride a reverse-handlebar bike much more quickly than someone who hasn't. I'll bet that I can learn to ride such a bike in an hour if I had an open space free of obstacles to practice in (like a parking lot). The reason I would need this is that initially I am not going to be able to control the direction of the bike, just keep it stable long enough to get up to speed and into the stable control regime. Like I said in the opening, if anyone knows where I can get my hands on such a bike so I can do this experiment please let me know.
Sunday, May 31, 2015
Thursday, May 07, 2015
Why Lisp?
A number of people have contacted me about a comment I wrote yesterday on Hacker News asking me to elaborate, e.g.:
The short version of the answer is that Lisp is not merely a different notation, it's a fundamentally different way of thinking about what programming is. The mainstream model is that programming consists of producing standalone artifacts called programs which operate on other artifacts called data. Of course, everyone knows that programs are data, but the mainstream model revolves around maintaining an artificial distinction between the two concepts. Yes, programs are data, but they are data only for a special kind of program called a compiler. Compilers are hard to write, a field of study unto themselves. Most people don't write their own compilers (except occasionally as academic exercises), but instead use compilers written by the select few who have attainted the level of mastery required to write one that isn't just a toy.
The Lisp model is that programming is a more general kind of interaction with a machine. The act of describing what you want the machine to do is interleaved with the machine actually doing what you have described, observing the results, and then changing the description of what you want the machine to do based on those observations. There is no bright line where a program is finished and becomes an artifact unto itself. Yes, it is possible to draw such a line and produce standalone executables in Lisp, just as it is possible to write interactive programs in C. But Lisp was intended to be interactive (because it was invented to support AI research), whereas C was not (because it was invented for writing operating systems). Interactivity is native to Lisp whereas it is foreign to C, just as building standalone executable is native to C but foreign to Lisp.
Of course, there are times when you have no choice but to iterate. Some times you don't know everything you need to know to produce a finished design and you have to do some experiments, and the faster you can do them the better off you will be. In cases like this it is very helpful to have a general mechanism for taking little programs and composing them to make a bigger program, and the C world has such a mechanism: the pipe. However, what the C world doesn't have is a standard way of serializing and de-serializing data. And, in particular, the C world doesn't have a standard way of serializing and de-serializing hierarchical data. Instead, the C world has a vast array of different kinds of serialization formats: fixed-width, delimiter-separated, MIME, JSON, ICAL, SGML and its offspring, HTML and XML, to name but a few. And those are just serialization formats for data. If you want to write code, every programming language has its own syntax with its own idiosyncrasies.
The C ecosystem has spawned the peculiar mindset that thinks that syntax matters. A lot of mental energy is devoted to syntax design. Tools like LEX and YACC are widely used. In the C world, writing parsers is a big part of any programmer's life.
Every now and then someone in the C world gets the bright idea to try to use one of these data serialization formats to try to represent code. These efforts are short-lived because code represented in XML or JSON looks absolutely horrible compared to code represented using a syntax specifically designed to represent code. They conclude that representing code as data is a Bad Idea and go back to writing parsers.
But they're wrong.
The reason that code represented as XML or JSON looks horrible is not because representing code as data is a bad idea, but because XML and JSON are badly designed serialization formats. And the reason they are badly designed is very simple: too much punctuation. And, in the case of XML, too much redundancy. The reason Lisp succeeds in representing code as data where other syntaxes fail is that S-expression syntax is a well-designed serialization format, and the reason it's well designed is that it is minimal. Compare:
The horrible bloatedness of XML is obvious even in this simple example. The difference between JSON and S-expressions is a little more subtle, but consider: this is a valid S-expression:
The JSON equivalent is:
Rendering that into XML is left as an exercise.
The difference becomes particularly evident if you try to type those expressions rather than just look at them. (Try it!) The quotes and commas that seem innocuous enough for small data structures become an immediately intolerable burden for anything really complicated (and XML, of course, like all SGML-derivatives, is just completely hopeless).
The reason that Lisp is so cool and powerful is that the intuition that leads people to try to represent code as data is actually correct. It is an incredibly powerful lever. Among other things, it makes writing interpreters and compilers really easy, and so inventing new languages and writing interpreters and compilers for them becomes as much a part of day-to-day Lisp programming as writing parsers is business as usual in the C world. But to make it work you must start with the right syntax for representing code and data, which means you must start with a minimal syntax for representing code and data, because anything else will drown you in a sea of commas, quotes and angle brackets.
Which means you have to start with S-expressions, because they are the minimal syntax for representing hierarchical data. Think about it: to represent hierarchical data you need two syntactic elements: a token separator and a block delimiter. In S expressions, whitespace is the token separator and parens are the block delimiters. That's it. You can't get more minimal than that.
It is worth noting that the reason the parens stick out so much in Lisp is not that Lisp has more parens than other programming languages, it's that Lisp as only one block delimiter (parens) and so the parens tend to stick out because there is nothing else. Other languages have different block delimiters depending on the kind of block being delimited. The C family, for example, has () for argument lists and sub-expressions, [] for arrays, {} for code blocks and dictionaries. It also uses commas and semicolons as block delimiters. If you compare apples and apples, Lisp usually has fewer block delimiters than C-like languages. Javascript in particular, where callbacks are ubiquitous, often gets mired in deep delimiter doo doo, and then it becomes a cognitive burden on the programmer to figure out the right delimiter to put in depending on the context. Lisp programmers never have to worry about such things: if you want to close a block, you type a ")". It's always a no-brainer, which leaves Lisp programmers with more mental capacity to focus on the problem they actually want to solve.
And on that note, I should probably get back to coding. Iteratively, of course :-)
[This post has been translated into Chinese and Japanese.]
my impression is that lisp is *only* a different notation. Is that correct, or am I missing something? I don't see why it is so important that lisp code matches the data structure (and my assumption is that the match is the answer to 'why lisp') - am I overlooking the importance of macros, or is there even more that I'm still not aware of?The answer to this question is long, so I thought I'd go ahead and turn it into a blog post.
The short version of the answer is that Lisp is not merely a different notation, it's a fundamentally different way of thinking about what programming is. The mainstream model is that programming consists of producing standalone artifacts called programs which operate on other artifacts called data. Of course, everyone knows that programs are data, but the mainstream model revolves around maintaining an artificial distinction between the two concepts. Yes, programs are data, but they are data only for a special kind of program called a compiler. Compilers are hard to write, a field of study unto themselves. Most people don't write their own compilers (except occasionally as academic exercises), but instead use compilers written by the select few who have attainted the level of mastery required to write one that isn't just a toy.
The Lisp model is that programming is a more general kind of interaction with a machine. The act of describing what you want the machine to do is interleaved with the machine actually doing what you have described, observing the results, and then changing the description of what you want the machine to do based on those observations. There is no bright line where a program is finished and becomes an artifact unto itself. Yes, it is possible to draw such a line and produce standalone executables in Lisp, just as it is possible to write interactive programs in C. But Lisp was intended to be interactive (because it was invented to support AI research), whereas C was not (because it was invented for writing operating systems). Interactivity is native to Lisp whereas it is foreign to C, just as building standalone executable is native to C but foreign to Lisp.
Of course, there are times when you have no choice but to iterate. Some times you don't know everything you need to know to produce a finished design and you have to do some experiments, and the faster you can do them the better off you will be. In cases like this it is very helpful to have a general mechanism for taking little programs and composing them to make a bigger program, and the C world has such a mechanism: the pipe. However, what the C world doesn't have is a standard way of serializing and de-serializing data. And, in particular, the C world doesn't have a standard way of serializing and de-serializing hierarchical data. Instead, the C world has a vast array of different kinds of serialization formats: fixed-width, delimiter-separated, MIME, JSON, ICAL, SGML and its offspring, HTML and XML, to name but a few. And those are just serialization formats for data. If you want to write code, every programming language has its own syntax with its own idiosyncrasies.
The C ecosystem has spawned the peculiar mindset that thinks that syntax matters. A lot of mental energy is devoted to syntax design. Tools like LEX and YACC are widely used. In the C world, writing parsers is a big part of any programmer's life.
Every now and then someone in the C world gets the bright idea to try to use one of these data serialization formats to try to represent code. These efforts are short-lived because code represented in XML or JSON looks absolutely horrible compared to code represented using a syntax specifically designed to represent code. They conclude that representing code as data is a Bad Idea and go back to writing parsers.
But they're wrong.
The reason that code represented as XML or JSON looks horrible is not because representing code as data is a bad idea, but because XML and JSON are badly designed serialization formats. And the reason they are badly designed is very simple: too much punctuation. And, in the case of XML, too much redundancy. The reason Lisp succeeds in representing code as data where other syntaxes fail is that S-expression syntax is a well-designed serialization format, and the reason it's well designed is that it is minimal. Compare:
XML: <list><item>abc</item><item>pqr</item><item>xyz</item></list>
JSON: ['abc', 'pqr', 'xyz']
S-expression: (abc pqr xyz)
The horrible bloatedness of XML is obvious even in this simple example. The difference between JSON and S-expressions is a little more subtle, but consider: this is a valid S-expression:
(for x in foo collect (f x))
The JSON equivalent is:
['for', 'x', 'in', 'foo', 'collect', ['f', 'x']]
Rendering that into XML is left as an exercise.
The difference becomes particularly evident if you try to type those expressions rather than just look at them. (Try it!) The quotes and commas that seem innocuous enough for small data structures become an immediately intolerable burden for anything really complicated (and XML, of course, like all SGML-derivatives, is just completely hopeless).
The reason that Lisp is so cool and powerful is that the intuition that leads people to try to represent code as data is actually correct. It is an incredibly powerful lever. Among other things, it makes writing interpreters and compilers really easy, and so inventing new languages and writing interpreters and compilers for them becomes as much a part of day-to-day Lisp programming as writing parsers is business as usual in the C world. But to make it work you must start with the right syntax for representing code and data, which means you must start with a minimal syntax for representing code and data, because anything else will drown you in a sea of commas, quotes and angle brackets.
Which means you have to start with S-expressions, because they are the minimal syntax for representing hierarchical data. Think about it: to represent hierarchical data you need two syntactic elements: a token separator and a block delimiter. In S expressions, whitespace is the token separator and parens are the block delimiters. That's it. You can't get more minimal than that.
It is worth noting that the reason the parens stick out so much in Lisp is not that Lisp has more parens than other programming languages, it's that Lisp as only one block delimiter (parens) and so the parens tend to stick out because there is nothing else. Other languages have different block delimiters depending on the kind of block being delimited. The C family, for example, has () for argument lists and sub-expressions, [] for arrays, {} for code blocks and dictionaries. It also uses commas and semicolons as block delimiters. If you compare apples and apples, Lisp usually has fewer block delimiters than C-like languages. Javascript in particular, where callbacks are ubiquitous, often gets mired in deep delimiter doo doo, and then it becomes a cognitive burden on the programmer to figure out the right delimiter to put in depending on the context. Lisp programmers never have to worry about such things: if you want to close a block, you type a ")". It's always a no-brainer, which leaves Lisp programmers with more mental capacity to focus on the problem they actually want to solve.
And on that note, I should probably get back to coding. Iteratively, of course :-)
[This post has been translated into Chinese and Japanese.]