This article introduces concatenative langauges, but it doesn't explain why they matter.
In my work, I found that the lack of syntactic marking for arguments of function calls is a devastating drawback. Coming back to my own function definitions a week after writing them, I spent minutes unpuzzling the code. I could use every trick and write the function in the most elegant way, using combinators in the style of Factor, and that made it worse. But writing it out with local bindings also didn't help. As soon as you write a nested expression, you start to lose the sense of which values are being passed where.
gcd n1 n2 n2 0 = if n1 else n2 n1 n2 mod gcd
gcd zero if else "mod" plus swap gcd
factorial 1 interval product
I was designing a Forth-like functional language with generic functions, and for a long time I felt that the lack of markings didn't matter. I thought that one could understand the code "well enough" without knowing exactly where the arguments were going. There is something to this argument, and there's a lot we can do to make code say what it does. But sometimes the author just had to implement something, and technicalities arose, and when you go to read it, the code doesn't "read" and you have to bring your own intelligence to figure out what it does -- it won't tell you. In these cases, explicit argument marking is indispensable.
In Forth-like languages, simple things are wonderful and elegant. There is no other shorter way to write than point-free. And, writing with combinators is satisfying, and it can make the "essence of the function" more evident. But unless you severely constrain your style to ultra short definitions, avoid nested expressions, and use local variables profusely, you're constructing puzzles for yourself.
It's almost like the concatenative style is too optimal. You have to back up a step in beauty in order to get a practical tool.
The two best-known features of Chuck Moore's style -- extreme simplicity and extreme factoring -- must be how he avoids the dangers you describe. I wonder if these qualities go beyond stylistic choice and are actually necessary if one is to build real systems in Forth. That might explain why programmers who come from other languages tend not to stick with it. Your story is reminiscent of others I've read in the past (most prominently http://www.yosefk.com/blog/my-history-with-forth-stack-machi...) that talk about being in love with the Forth model and then abandoning it because it got too complicated to make it do what they want.
Makes me wonder if trying to do what you want in that model is a recipe for disaster; instead, maybe you have to let the model tell you what you can do: if it's simple you get to do it and if it's not you don't. Chuck would see that as an advantage, but most programmers wouldn't.
Edit: the article I linked to talks about that at length. His conclusion is that if you're going to build systems in Forth, you need the freedom to shrink or morph the problem into something that can be solved simply in Forth. If you don't have that freedom (e.g. because people are feeding you inflexible requirements), it probably won't work...
In my work, I found that the lack of syntactic marking for arguments of function calls is a devastating drawback. Coming back to my own function definitions a week after writing them, I spent minutes unpuzzling the code. I could use every trick and write the function in the most elegant way, using combinators in the style of Factor, and that made it worse. But writing it out with local bindings also didn't help. As soon as you write a nested expression, you start to lose the sense of which values are being passed where.
gcd n1 n2 n2 0 = if n1 else n2 n1 n2 mod gcd
gcd zero if else "mod" plus swap gcd
factorial 1 interval product
I was designing a Forth-like functional language with generic functions, and for a long time I felt that the lack of markings didn't matter. I thought that one could understand the code "well enough" without knowing exactly where the arguments were going. There is something to this argument, and there's a lot we can do to make code say what it does. But sometimes the author just had to implement something, and technicalities arose, and when you go to read it, the code doesn't "read" and you have to bring your own intelligence to figure out what it does -- it won't tell you. In these cases, explicit argument marking is indispensable.
In Forth-like languages, simple things are wonderful and elegant. There is no other shorter way to write than point-free. And, writing with combinators is satisfying, and it can make the "essence of the function" more evident. But unless you severely constrain your style to ultra short definitions, avoid nested expressions, and use local variables profusely, you're constructing puzzles for yourself.
It's almost like the concatenative style is too optimal. You have to back up a step in beauty in order to get a practical tool.