This isn’t concatenative except in the trivial sense of “stack-based”. Concatenative languages are functional languages with compositional semantics, which often happen to be most efficiently implemented as stack machines. Concatenative languages are interesting because they’re a combinator calculus like SKI[1] but with simpler semantics and useful algebraic properties.Only allowing two-argument functions doesn’t cut it, and you need some means of returning multiple values as well. You also need a means of abstraction (e.g., Clojure fns) and combinators for application, abstraction, and stack manipulation. A full implementation of an interpreter for a concatenative DSL would be rather longer than this—though still probably in the realm of 100 lines.

 Fogus linked to my project, Factjor:https://github.com/brandonbloom/factjorFactjor supports quotations, currying, composition, and has most of the primary combinators: dip, keep, cleave, spread, application, etc. It's only about 100 lines.
 > Concatenative languages are interesting because they’re a combinator calculus like SKI but with simpler semantics and useful algebraic properties.It's difficult to have simpler semantics than SK calculus. Perhaps a more appropriate modifier in this instance would be "more convenient".
 Yes, that’s fair. The example I had in mind was to do with GC: I’m not sure you can implement an SK interpreter without it.
 I'm not sure that the presense of a stack is required for a concatenative language, but your point is well taken. Pesto5 is not enterprise ready.
 Right, that’s what I said. Just because it’s efficient to implement one language that way doesn’t mean it’s efficient to do that for every language in the same family. :)With non-variadic arithmetic functions:`````` (defn add [x] (cons (+ (first x) (second x)) (rest (rest x)))) `````` Your “postfix” function can remain a simple “reduce”, but can be totally agnostic of function arity. That frees you up to write the basic combinators:`````` (defn dup [x] (cons (first x) x)) (defn zap [x] (rest x)) (defn swap [x] (cons (second x) (cons (first x) (rest (rest x))))) (defn ap [x] (apply (first x) (rest x))) ...``````
 A data stack is indeed not required -- see Om (experimental):http://concatenative.org/wiki/view/OmIt uses prefix notation: instead of a data stack, each function takes the remainder of the program for rewriting.
 I whether or not there is a stack is similar to the complementary nature of foldL vs parallel fold (ie Clojure's core/reduce vs reducers). Left-to-right concatenative languages make use of a stack and are appropriate for side effects and stream processing. However, there are pure concatenative languages that operate in parallel via term rewriting, which has a computational model akin to that of a DNA computer.
 Enchilada is a concatenative language which is not stack based but instead works through term rewriting.
 You seem to have missed the point of this fun little exercise. Search for "in no way indicative" and "debatable" in the OP.
 No no, I only said this for the benefit of others who might not be familiar with concatenative programming. The OP clearly knows what they’re doing.
 I, for one, appreciated the clarification.

Search: