Tuesday, February 15, 2011

Critique of Reason

A language will not succeed without a good name. I have recently invented a very good name and now I am looking for a suitable language.
                — Donald Knuth

Louis Reasoner is developing a new computer language. I'm letting him write this post.

“I have already done the most important part: the name of my language is Reason.

“The second most important thing is to come up with a trope. This will enable me to defend my language decisions with a pithy reply and call it a design philosophy. My trope is ‘reasonableness’. Reason will adhere to the philosophy of reasonableness. Anything in my language is, by definition, reasonable. Anything omitted is naturally unreasonable. Here is some more design philosophy:
  • Small is more reasonable than big.
  • Fast is more reasonable than slow.
  • Useful is more reasonable than useless.
  • Good is more reasonable than bad.
  • etc., etc., etc....
I'll generate more later.

“After the name and the self-styled philosophy, the next important thing is the syntax. The syntax of Reason is complicated, but reasonable. Bear with me. Although it might be a bit difficult to explain, it is, after sufficient practice, natural to use.

Reason borrows heavily from Lisp and Scheme. Most of the programming in Reason is done in ‘Lisp’ mode. Lisp mode is exactly what you think it would be: you write programs just like you would in Lisp, but with a few modifications to make things more reasonable.
  • Prefix notation for everything by default, with these exceptions:
    • Infix notation for arithmetic. — Let's just capitulate on this one. Operator precedence will be fleshed out later.
    • Excess parenthesis are ignored where it is unambiguous. You can pretty much always add parenthesis to make something clearer or to override operator precedence.
    • Function calls have the operator on the outside of the parenthesis. Not only is this more natural, it avoids weird interactions with operator precedence. Arguments are separated by commas.
    • Postfix notation for post-increment and post-decrement. — I just like these.
  • No ‘special’ forms. We get rid of
    • define — Lisp code tends to creep towards the right margin. Removing internal definitions makes the code ‘flatter’ and therefore easier to read. (Besides, it's hard to efficiently compile internal definitions.)
    • begin — No good reason to include it.
    • cond — Too many parenthesis.
    • let — Again, too many parenthesis.
    • lambda — This is just too advanced. Mere mortals can define a named procedure like anyone else would.
    • letrec — As if lambda wasn't confusing enough! Who comes up with this stuff?
    • quote — Too confusing. Actually, I wanted to leave quote in, but with infix and postfix in the mix I couldn't figure out where the quotation ended. I decided to punt.
  • Assignment is allowed. This is technically a ‘special form’, but it is so useful that I had to leave it in.
“Lisp mode is distinguished by its use of nesting as the primary means of combination. In fact, sequential combinations are disallowed. Lisp mode constructs are created compositionally from other Lisp mode constructs or primitives. Lisp mode is where most of the primitive procedures of the language are available.

“In order to radically simplify Lisp mode I had to introduce ‘Program’ mode. Program mode is more imperative than Lisp mode, so I tried to reduce the functionality and power of Program mode so that people would favor Lisp mode. Program mode has these features:
  • Special forms — Flow control, variable declaration and binding, conditionals, etc. are available in Program mode.
  • No artificially rigid syntax — Program mode is not really infix, prefix, or postfix. Each construct defines its own syntax. This improves readability for the built-in special forms. For example, the if construct can have a traditional else clause rather than just having two or three subconstructs like in Lisp.
  • No user-defined special forms — The user doesn't have to memorize any additional special forms beyond the built-in ones.
  • No arbitrary nesting — In Program mode, you can only nest a construct if the enclosing construct permits it. There is nesting, it is just controlled.
  • Concatenation for a means of combination — Lisp mode is obviously recursively evaluated. This isn't needed in Program mode because arbitrary nesting is disallowed. Instead, user constructs in Program mode are built by concatenation of Program mode primitives.
  • Easy switching to Lisp mode — You can always concatenate a Lisp mode construct with a Program mode construct. Originally, I didn't want to do this, but I ended up duplicating a lot of the Lisp mode functionality. By allowing the programmer to switch to Lisp mode pretty much whenever he wants, I avoided having to duplicate a lot of code.
“When you write a procedure in Reason, you start in Program mode. As I mentioned, you can switch to Lisp mode whenever you feel like it, but there is no way to switch back (this isn't strictly true, you can mimic the ability to switch back by use of a function call. The function body starts in Program mode.) You can define a procedure in either Program mode or Lisp mode. That is, you can explicitly mark a procedure as available in Program mode only or in Lisp mode only. Of course since you can always switch to Lisp mode, it makes no discernible difference if you define a procedure as Lisp mode only; you can use it in Program mode. But if you define a procedure in Program mode only, you simply cannot use it from Lisp mode. (It will be visible, you just can't call it.)

“I could go on for hours about how variables are looked up, but I don't want to bore everyone. I would like some feedback about my ideas so far, though.

How about it? Would any readers care to critique the design of Reason?


drcode said...

It's an interesting idea on the surface, hiding all the ugly imperative stuff in sort of a "meta" language in order to maintain a clean core. I think the "program mode" language should look a lot like "pseudocode" as does Python.

The one concern I have is that imperative constructs are often useful within an FP code within a delimited area (see Clojure "pods"). Seems like your design would prevent this use. I wonder if there's any way to allow "program mode" logic in a "lisp mode" function as long as it's not exposed to the outside world.

Warren Wilkinson said...

Is reasonable-ness judge the merit of 'tail calls optimization', recursion, jump tables, co-routines, or continuations?I could see reasonable as omitting all but the first --- but not long ago, reasonable was having none.

Lisp implementations are massive. I wouldn't want to rebuild one for anything less than massive improvement.

Best of luck to you regardless.

Unknown said...

When you said you were removing lambda, I started thinking you were writing a satire.
I was surprised that there was no mention of macros.
Maybe consider adding quote in a different form, that allows you to specify the end of the 'quote'.
While I admire the thought you put into this, I don't like how it restrains the programmer.
As an example, Ruby has gotten popular by removing the parentheses without the freedoms. It embeds DSLs where appropriate to reduce code duplication.
What benefits do the two modes provide over embedded DSLs or straight lisp?

mquander said...

Figures! If Alyssa P. Hacker had been in charge instead, I bet we'd be better off now!

Famous last words: I tried to reduce the functionality and power of Program mode so that people would favor Lisp mode.

mquander said...

Casey, now that we have much nicer-looking code in Lisp-mode, with infix notation and less parentheses, maybe we can just have utterly simple text-substitution macros instead? Those are sure to be easy to read and unambiguous.

Nathan said...

Seems like this language has already been created. It's called 'C', and in some circles it's pretty popular.

Nathan said...
This comment has been removed by the author.
Anonymous said...

It doesn't seem very reasonable to have two different editing modes. It could lead to a lot of confusion--coding conventions would be harder to enforce and code would be harder to read.

r said...

I'm not sure exactly what you're sniping at here, but it's an entertaining snipe.

Unknown said...

R6RS intro: "Programming languages should be designed not by piling feature on top of feature, but by removing the weaknesses and restrictions that make additional features appear necessary. Scheme demonstrates that a very small number of rules for forming expressions, with no restrictions on how they are composed, suffice to form a practical and efficient programming language that is flexible enough to support most of the major programming paradigms in use today."

Anonymous said...

I was sure you meant your final question to be "does anyone want to critique the design of Java?".

Unknown said...

I just started to reason about Reason, and am currently stuck in a recursive inner loop, switching continuously the program mode...

Fortunately, human thinking is slow (really slow), and human brain memory is huge (really huge), so I will not end up in some stack overflow prior to my (inevitable) d*** (I censured myself, because this is a tabu word for most modern minds, outside of religion, obviously).

I wish your readers best luck with really understanding your philosophy!

Unknown said...

I'd lost track of Louis after he was hired by (redacted); it's good to see he's out and about and doing as good work as ever.

Let's start off with the fact that he presents no reason for Reason, no class of problems for which it is suited, no software engineering justification, no research question that Reason would help solve. It's nice to have a manifesto, but something better than 'useful is better than useless' is needed. What are the characteristics of
problems that Reason is well-suited to solve?

Second, Louis is premature in announcing Reason. He needs at least one example of a program in it; he must then demonstrate why Reason solves this problem better than other languages.

Third, Louis's design strategy seems to be a mixture of random hacking and elevation of personal preferences to Cosmic Laws. At the very least, he needs to separate design from rationale.

I could say more, but that's a start.

Unknown said...

In my earlier comment, I neglected to add my biggest objection to Louis's project, the lack of a strictly (or lazily) functional subset. If that had been supplied, it would have been called Pure Reason, and then we could have called in Immanuel Kant to review it.

My apologies.

Sameer Siddiqui said...