On a whim, I picked Factor back up yesterday. By coincidence, Alvaro Videla had also returned to it at about the same time. In a Twitter conversation on the topic, he asked a couple of interesting questions. Since Twitter is not a good medium for more elaborate discussion, I’m posting my responses here.
I should add that I am only a beginner in Factor, and I’m answering these questions on the basis of whatever little I know. If there are errors in this post, please feel free to correct them.
Q: What’s your take on Factor macros vs Lisp ones?
A: Factor macros have considerably simpler semantics. Thanks to “concatenativity”, macro expansion simply involves splicing a sequence. Nothing more. Thanks to the same property, Factor macros, unlike their Lisp counterparts, compose.
One downside I can think of is that Factor macros provide no mechanism for maintaining hygiene. You are on your own. Probably because relying on named cells is not in the vein of the language. Or perhaps it was simply an oversight. I do not know. Maybe I should pose the question to the wizards at #concatenative.
Note that macros are not used very often in Factor. Factor uses parsing words for most of the things Lisps use macros for. Parsing words are somewhat like reader macros.
Compare TUPLE: vs defrecord, GENERIC: vs defmulti, USING: vs use, and so on.
Q: If you compare Lisp vs Factor in the Paul Graham sense, what do you think?
A: Comparing against this list:
- Conditionals: Check.
- Function types: Check. In Factor parlance, functions are called words. Words are simply named quotations; quotations are sequences; sequences are data. So even function “contents” are first-class values. In that respect, it goes even further than Lisp. This enables things like invertible quotations.
- Recursion: Check, with full TCO. Note that in Factor you rarely use recursion directly in your code. Sequence combinators can usually achieve the same ends in a more elegant manner.
- Variables 2.0: Check.
- GC: Check.
- Programs composed of expressions: Check.
- Symbols: Check.
- A notation for code using tree of symbols: Irrelevant.
- The whole language always available: Check.
Factor meets all of the key stated goals of Lisp. There are many similarities between the two, and you can see a clear Lisp influence in many aspects of Factor. Even so, it is not a Lisp.
The stack model is quite different from Lisp’s inside-out model. It necessitates things like make and fry, which are not required in Lisp. Rest parameters have no meaning in a stack-language context, so it is common to define words specialized for arities up to a certain value, usually 3, and a more general word that operates on a sequence. Keyword arguments do not exist either. On the other hand, there are corresponding advantages to the stack model, many of which are listed on concatenative.org.
More importantly, Factor is concatenative whereas Lisp is applicative. That means Factor does not have lambdas as part of the language, nor let bindings. There is library support for both, but they desugar to tacit expressions. So there is no connection with lambda calculus in the usual sense. Factor is more in line with Backus’ function-level programming than with lambda calculus, although the official Factor site and blog do not seem to touch on these topics.
For what it’s worth, I still find Factor more compelling than Lisp.
Recommended reading: