Read-Eval-Print-λove – Forth Thinking
leanpub.com
leanpub.com
Starting Forth : http://www.forth.com/starting-forth/
Thinking Forth : https://sourceforge.net/projects/thinking-forth/files/
(Mirror) http://www.dnd.utwente.nl/~tim/colorforth/Leo-Brodie/thinkin...
These are provided by the author (http://www.forth.com/forth/forth-books.html).
Some (e.g. Factor) do offer pattern matching/multimethods which are generally much cleaner.
Dealing with that may require to thing out of the box a bit, and forget about what is "good" and "bad" in other languages. Maybe you can use table-driven programming? Maybe you can do some dirty tricks with the return stack to get the control-flow you want? Maybe you really have to put that data in a variable? There's no single answer, and it can get ugly at times.
Not, BTW, ugly like in the article. This:
> : apply2 rot dup rot dip rot apply swap ;
... is an abomination. "dip" is questionable already. "rot", thought part of the standard, is best avoided. Because one should only deal with the top two elements of the stack. And of course "apply2" itself is suspicious.
Why the author showed this, even though he seems knowledgeable enough to know that he shouldn't? Because he picked a simplified Forth that did not let him use the return stack.
The author sure talks a lot about the "Forth philosophy" but apparently missed one or two things about it. If one wants to talk about philosophy, one should at least include in the bibliography what his inventor says about Forth (http://www.ultratechnology.com/forth0.htm - a lot of stuff there, the main piece being 1xForth). I believe it's Moore that said something like "The important thing is not what you add, but what you remove". The return stack is a core component of Forth; picking a "simplified" Forth that won't let you use it ... well that language shouldn't be called Forth to begin with. That's a bad choice.
There are also other questionable choices like using [ ] for "quotations" when they are used for something totally different in standard Forth. Introducing "quotations" is also questionable in itself. It only looks easily implemented because Ruby provides all the memory management; but in reality implementing an interpreter on top of an interpreter is not viable (that makes like at least a x1000 slowdown relative to C); Forth interpreters are typically written in low level compiled languages (typically C), which don't provide garbage collection. And in the end, those "quotations" only look cute. What really helps is currying.
Forth is ugly, stupid and mean. It's up to you to find clever ways to write nice-looking programs.
That said, I suspect that nesting conditional statements 3 or even 2 levels deep would become difficult to read. As a result, it'd probably be best to factor out various tests into their own words to keep things readable.
So this line of Forth:
3 4 < IF ." OK" ELSE ." WAT" THEN
Means: Evaluate "3 < 4". If it's true, print "OK", otherwise print "WAT". The "IF" "ELSE" and "THEN" words are compile time words. When that line of code is entered, before it's run, they get expanded to something like: 3 4 < ?BRANCH 5 LIT "OK" OUTPUT BRANCH 3 LIT "WAT" OUTPUT
Here, "?BRANCH" is a conditional jump followed by an offset and "BRANCH" is an unconditional jump. Those are built-in and will move the instruction pointer directly, so you get the conditional evaluation you need.Other stack based languages do this differently. In Factor, it would be:
3 4 < [ "OK" print ] [ "WAT" print ] if
Here, "[" and "]" are "parse words" that at parse time wrap of their contained words and create a quotation out of them. Basically like a closure or thunk—a chunk of code to be executed later if desired. So this code evaluates the condition and puts it on the stack. Then it pushes two quotations onto the stack. Then the "if"[2] word executes. It's just a regular word now. It looks at the condition and, if true, executes the first quotation. Otherwise it runs the second.In this sense, Factor works like Smalltalk where control flow doesn't need to be special because the language has very terse syntax for explicitly creating a deferred chunk of code[3].
[1]: https://en.wikipedia.org/wiki/Forth_(programming_language)
[2]: http://docs.factorcode.org/content/word-if%2Ckernel.html
[3]: https://www.gnu.org/software/smalltalk/manual/html_node/Cond...
I think that his intended readership is expected to be more familiar with Clojure than with Ruby.
Why is it funny that a magazine about Lisps has code in Lisp? I'm not seeing the humor.
I don't believe that Lucida Console or Monaco is a terribly good face, but neither of them exhibits the behaviour you report, so it's probably a problem with your browser font configuration.
I currently recommend Source Code Pro for monospace, Linux Libertine for serif and Linux Biolinum for sans-serif. These are the most attractive & legible fonts I've yet found for day-to-day use, but I'm glad to hear of others' findings.