So called concatenative language is also a combinator-oriented language in a somewhat restricted form. Here are some historic examples of combinator-oriented languages: APL family and Backus's FP/FL (direct inspiration for the author of Joy). The fact that you denote composition of the functions with a white spaces is just a syntactic sugar. In the case of combinator-oriented language you work with various functional forms -- combinators, not just with composition, so you need to use more symbols to denote that. And in practice it's hard to find a concatenative language which would be used seriously, not just in a few hobby projects. In the same time there are impressive examples of modern combinator-oriented languages like Faust [1] and Spiral [2].
Still, the whole "concatenative" movement is interesting as a try to formalize the semantics and "improve" Forth language. See also Postscript and Henry Backer's articles [3].
In a general sense, yes, of course. Here are more examples.
1. BNF notation. Yes, it could be surprising, but in a BNF-like language we use function-level representation and white spaces here denote sequential composition of functions -- nonterminals.
2. In a some Lisp-like language one may use spaces to describe "abstract" composition. So, for sequential composition: "(seq func1 func2 func3)". And for parallel composition, for example: "(par func1 func2 func3)".
But in the case of real concatenative programming, which has its origin in Forth, you mostly deal with stacks and stack machines.
In q it's just {(q%x),z%q:-.5y+signum[y]sqrt(yy)-4xz}
This is easy to see is correct.
How do you know that Joy is correct?
I'm trying to mentally execute this. I know I haven't seen Joy before, but I've used Forth, Postscript and Lisp, so I feel like I have a lot to stand on:
- cons seems to have the same meaning in lisp, so x y cons -> (x . y) or in Erlangish, [x|y] right?
- x [y] dip seems to be y x
- [x] [y] infra seems to be the same as [x y]
- swap, first, pop, sqrt all seem reasonable
- wouldn't [] cons cons cons dup* be better than the extra list with [i] map ] infra first? it's not really clear to me what [i] map is doing... I see how the values have to flow, but it feels like it should be redundant.
I feel like it's immediately a lot more (mental) work. It reminds me of tracing forth code before I just gave in and started using variables like a normal person.
Is this really the best way to be introduced to Joy? Is this a typical problem that Joy programmers feel is the right way to program (and the right solution?) Am I missing something here?
to be on their own line (indented two spaces), but that way Arc won't chew them. I'm mentioning this because I can't determine the original text myself.
I haven't done much with concatenate languages, but a rule of thumb is that if you see a bunch of dips, dups, and swaps, then you are probably doing something wrong. Those should be encapsulated in simple definitions.
I've been working on a dialect of Joy recently.[1] It's implemented in Python, in the Continuation-Passing Style. I've implemented type inference[2] and I'm almost done with a compiler (to Python for now.)
Joy combines the best features of Forth and Lisp.
It also makes "Categorical Programming" easy.[3] You can get a variety of valid computations by instantiating the same code over different categories. For example, the Joy type inferencer is an interpreter that operates on stack effect representations rather than e.g. numbers and strings. The same Joy expression that, when run on the normal interpreter gives the calculation, gives the stack effect of the expression when run on the inferencer. A subset of functions has to be overridden to make this work, but then you're good-to-go.
The mental models that you have to adopt to develop in Joy are better than those for other languages. There's a purity and elegance in the Joy notation that continues to be very exciting and interesting. For example, check out "Recursion Combinators"[4] which is loosely based on the first part of the "Bananas, Lenses, & Barbed Wire" paper[5].
My interest is binary: 1.) Joy is a notation and semantics that normal everyday people can easily understand and use; I've developed a user interface based on Joy as the unifying, uh, interface (both GUI and text interaction result in a stream of Joy commands) and I'm going to be setting up "encounter groups" and live user testing starting this month. I'm going to put normal people in front of a raspberry pi that's configured as a kind of Joy kiosk and see what happens.
2.) Joy is an excellent vehicle for developing proven-correct code. Most Joy development is more akin to deriving mathematical proofs than "regular" programming. Joy delivers on the promise of Functional Programming: making software by doing math. In Joy it's easy. I can write parsers that translate existing code into Joy-as-AST and then do refactoring and simplification. Recently, (the last couple of days) I've been playing with Prolog to represent Joy code. This has worked really well. It should be easy to make powerful code transformation tools.
Anyhow, to sum up: Joy is really cool. It's enormously simple and oh so elegant. Y'all should check it out.
Joy has come up a few times. A powerful language built on a few clever principles is alluring, but I found it impossible to read, sadly (but I feel somewhat similar about Forth).
Still, the whole "concatenative" movement is interesting as a try to formalize the semantics and "improve" Forth language. See also Postscript and Henry Backer's articles [3].
[1] http://faust.grame.fr/
[2] http://www.spiral.net/
[3] http://home.pipeline.com/~hbaker1/ForthStack.html