29

I've read the Wikipedia article on concatenative languages, and I am now more confused than I was when I started. :-)

What is a concatenative language in stupid people terms?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jason Baker
  • 192,085
  • 135
  • 376
  • 510
  • Just out of curiosity, why was the tutorial tag added? I'm not really looking for a tutorial... – Jason Baker May 25 '09 at 16:13
  • I think the title might be better as "Explanation of concatenative languages for 8 year olds." The current title makes me think of "what concatenative languages would be good for 8 year olds?" – Dan Lew May 25 '09 at 16:15
  • @Daniel Lew - Point taken. I've renamed the question. – Jason Baker May 25 '09 at 16:18
  • 7
    8 year old != stupid – Ates Goral May 25 '09 at 16:21
  • 3
    @Ates Goral - I know. In the interests of fairness, I will accept explanations that work for stupid people in addition to answers that work for 8 year olds. A more accurate title for this question would have been "Explain concatenative languages to me as though I have a diminished understanding of programming language concepts", but this one just seems to work better. :-) – Jason Baker May 25 '09 at 16:25
  • 11
    @Ates Goral ... true, but they do lack experience meaning that you have to explain things in detail without relying on them having a deep understanding of basically any domain what-so-ever. So thinking how would I explain this to a eight-year-old puts you in a headspace where you know you can't say things like: "a monad is a monoid in the category of endofunctors, what's the problem?" – Aaron Maenpaa May 25 '09 at 16:27
  • Maybe [this post](http://evincarofautumn.blogspot.com/2012/02/why-concatenative-programming-matters.html) can be very helpful. – brandizzi Feb 13 '12 at 00:23
  • Related: the blog post *[Why Concatenative Programming Matters](http://evincarofautumn.blogspot.dk/2012/02/why-concatenative-programming-matters.html)* by Stack Overflow user [Jon Purdy](http://stackoverflow.com/users/246886/jon-purdy) (brandizzi's comment stated in another way). – Peter Mortensen Jun 18 '12 at 01:06
  • This answer is what you're looking for: http://stackoverflow.com/a/12409746/2111193 – Spyryto Jun 30 '16 at 16:46

7 Answers7

19

In normal programming languages, you have variables which can be defined freely and you call methods using these variables as arguments. These are simple to understand but somewhat limited. Often, it is hard to reuse an existing method because you simply can't map the existing variables into the parameters the method needs or the method A calls another method B and A would be perfect for you if you could only replace the call to B with a call to C.

Concatenative language use a fixed data structure to save values (usually a stack or a list). There are no variables. This means that many methods and functions have the same "API": They work on something which someone else left on the stack. Plus code itself is thought to be "data", i.e. it is common to write code which can modify itself or which accepts other code as a "parameter" (i.e. as an element on the stack).

These attributes make this languages perfect for chaining existing code to create something new. Reuse is built in. You can write a function which accepts a list and a piece of code and calls the code for each item in the list. This will now work on any kind of data as long it's behaves like a list: results from a database, a row of pixels from an image, characters in a string, etc.

The biggest problem is that you have no hint what's going on. There are only a couple of data types (list, string, number), so everything gets mapped to that. When you get a piece of data, you usually don't care what it is or where it comes from. But that makes it hard to follow data through the code to see what is happening to it.

I believe it takes a certain set of mind to use the languages successfully. They are not for everyone.

[EDIT] Forth has some penetration but not that much. You can find PostScript in any modern laser printer. So they are niche languages.

From a functional level, they are at par with LISP, C-like languages and SQL: All of them are Turing Complete, so you can compute anything. It's just a matter of how much code you have to write. Some things are more simple in LISP, some are more simple in C, some are more simple in query languages. The question which is "better" is futile unless you have a context.

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
  • 2
    Good explanation, but I'm left wondering why concatenative languages should ever be used in place of something like LISP - it just seems like a subset of the functionality that list-based languages can do. (In other words, could you elaborate on how a concatenative language's list/stack processing is anything but a more restricted version of other languages?) – Dan Lew May 25 '09 at 17:15
  • Nice answer, with one nitpick - do you mean Turing Complete? – Dan Vinton May 27 '09 at 21:19
  • 2
    Another nitpick: SQL by itself isn't Turing complete. Although most DBMSes have extensions that make them Turing complete (this is what T-SQL, pl/SQL, etc mean) – Jason Baker May 27 '09 at 21:39
  • Fixed Turing :) And Jason's right: Without a loop that runs indefinitely, a language can't be Turing complete. – Aaron Digulla May 28 '09 at 06:59
  • This description brings JavaScript to mind, with how the lines between variables and functions seem to blur... is that at all right? I've never heard this term before either. – Alex Gosselin Sep 30 '10 at 04:06
  • There is some overlap in how different languages solve the same problem, so you'll see the same (or similar) solution in many places. What I'm still missing is a language which allows you to change the parser at runtime. I don't mean like LISP, I mean like "change the parser to include a piece of LISP in Java code without any escaping". Or maybe `HTML html = ...;` with syntax checking and variable expansion right in a Java method. – Aaron Digulla Sep 30 '10 at 07:05
  • Lisp is much simpler than e.g. SQL, C, Perl or Haskell. Forth is much simpler than Lisp. A good reason to look at Forth! – Sam Watkins Feb 22 '12 at 14:23
  • 2
    @SamWatkins: RPN allows for compact code but is not simple to understand because you need to reorder things/simulate a stack in your head. – Aaron Digulla Feb 22 '12 at 16:31
16

First I'm going to make a rebuttal to Norman Ramsey's assertion that there is no theory.

Theory of Concatenative Languages

A concatenative language is a functional programming language, where the default operation (what happens when two terms are side by side) is function composition instead of function application. It is as simple as that.

So for example in the SKI Combinator Calculus (one of the simplest functional languages) two terms side by side are equivalent to applying the first term to the second term. For example: S K K is equivalent to S(K)(K).

In a concatenative language S K K would be equivalent to S . K . K in Haskell.

So what's the big deal

A pure concatenative language has the interesting property that the order of evaluation of terms does not matter. In a concatenative language (S K) K is the same as S (K K). This does not apply to the SKI Calculus or any other functional programming language based on function application.

One reason this observation is interesting because it reveals opportunities for parallelization in the evaluation of code expressed in terms of function composition instead of application.

Now for the real world

The semantics of stack-based languages which support higher-order functions can be explained using a concatenative calculus. You simply map each term (command/expression/sub-program) to be a function that takes a function as input and returns a function as output. The entire program is effectively a single stack transformation function.

The reality is that things are always distorted in the real world (e.g. FORTH has a global dictionary, PostScript does weird things where the evaluation order matters). Most practical programming languages don't adhere perfectly to a theoretical model.

Final Words

I don't think a typical programmer or 8 year old should ever worry about what a concatenative language is. I also don't find it particularly useful to pigeon-hole programming languages as being type X or type Y.

cdiggins
  • 17,602
  • 7
  • 105
  • 102
5

After reading http://concatenative.org/wiki/view/Concatenative%20language and drawing on what little I remember of fiddling around with Forth as a teenager, I believe that the key thing about concatenative programming has to do with:

  • viewing data in terms of values on a specific data stack
  • and functions manipulating stuff in terms of popping/pushing values on the same the data stack

Check out these quotes from the above webpage:

There are two terms that get thrown around, stack language and concatenative language. Both define similar but not equal classes of languages. For the most part though, they are identical.

Most languages in widespread use today are applicative languages: the central construct in the language is some form of function call, where a function is applied to a set of parameters, where each parameter is itself the result of a function call, the name of a variable, or a constant. In stack languages, a function call is made by simply writing the name of the function; the parameters are implicit, and they have to already be on the stack when the call is made. The result of the function call (if any) is then left on the stack after the function returns, for the next function to consume, and so on. Because functions are invoked simply by mentioning their name without any additional syntax, Forth and Factor refer to functions as "words", because in the syntax they really are just words.

This is in contrast to applicative languages that apply their functions directly to specific variables.

Example: adding two numbers.

Applicative language:

int foo(int a, int b)
{
    return a + b;
}

var c = 4;
var d = 3;
var g = foo(c,d);

Concatenative language (I made it up, supposed to be similar to Forth... ;) )

push 4
push 3
+
pop

While I don't think concatenative language = stack language, as the authors point out above, it seems similar.

J. Polfer
  • 12,251
  • 10
  • 54
  • 83
5

I reckon the main idea is 1. We can create new programs simply by joining other programs together.

Also, 2. Any random chunk of the program is a valid function (or sub-program).

Good old pure RPN Forth has those properties, excluding any random non-RPN syntax.

In the program 1 2 + 3 *, the sub-program + 3 * takes 2 args, and gives 1 result. The sub-program 2 takes 0 args and returns 1 result. Any chunk is a function, and that is nice!

You can create new functions by lumping two or more others together, optionally with a little glue. It will work best if the types match!

These ideas are really good, we value simplicity.

It is not limited to RPN Forth-style serial language, nor imperative or functional programming. The two ideas also work for a graphical language, where program units might be for example functions, procedures, relations, or processes.

In a network of communicating processes, every sub-network can act like a process.

In a graph of mathematical relations, every sub-graph is a valid relation.

These structures are 'concatenative', we can break them apart in any way (draw circles), and join them together in many ways (draw lines).

Well, that's how I see it. I'm sure I've missed many other good ideas from the concatenative camp. While I'm keen on graphical programming, I'm new to this focus on concatenation.

Sam Watkins
  • 7,819
  • 3
  • 38
  • 38
1

My pragmatic (and subjective) definition for concatenative programming (now, you can avoid read the rest of it):

-> function composition in extreme ways (with Reverse Polish notation (RPN) syntax):

( Forth code )
: fib
  dup 2 <= if
    drop 1
  else
    dup 1 - recurse
    swap 2 - recurse +
  then ;

-> everything is a function, or at least, can be a function:

( Forth code )
: 1 1 ; \ define a function 1 to push the literal number 1 on stack

-> arguments are passed implicitly over functions (ok, it seems to be a definition for tacit-programming), but, this in Forth:

a b c

may be in Lisp:

(c a b)
(c (b a))
(c (b (a)))

so, it's easy to generate ambiguous code... you can write definitions that push the xt (execution token) on stack and define a small alias for 'execute':

( Forth code )
: <- execute ; \ apply function

so, you'll get:

a b c <- \ Lisp: (c a b)
a b <- c <- \ Lisp: (c (b a))
a <- b <- c <- \ Lisp: (c (b (a)))
Dmitri Zaitsev
  • 13,548
  • 11
  • 76
  • 110
0

You can't explain a language, just get one (Factor, preferably) and try some tutorials on it. Tutorials are better than Stack Overflow answers.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
alamar
  • 18,729
  • 4
  • 64
  • 97
  • 2
    That helps me understand *a* concatenative language. But it doesn't necessarily help me understand concatentative language *in general*. – Jason Baker May 25 '09 at 16:12
  • 3
    You shouldn't try to understand it *in general* until you learn one of these. – alamar May 25 '09 at 16:32
  • 3
    While his response doesn't answer your question, I'm gonna have to agree with alamar here. I would definitely pickup a Forth interpreter and a Forth book and try fiddling around. It's a different way of thinking about coding than most procedural languages do in terms of variables. – J. Polfer May 27 '09 at 21:46
0

To your simple question, here's a subjective and argumentative answer.

I looked at the article and several related web pages. The web pages say themselves that there isn't a real theory, so it's no wonder that people are having a hard time coming up with a precise and understandable definition. I would say that at present, it is not useful to classify languages as "concatenative" or "not concatenative".

To me it looks like a term that gives Manfred von Thun a place to hang his hat but may not be useful for other programmers.

While PostScript and Forth are worth studying, I don't see anything terribly new or interesting in Manfred von Thun's Joy programming language. Indeed, if you read Chris Okasaki's paper on Techniques for Embedding Postfix Languages in Haskell you can try out all this stuff in a setting that, relative to Joy, is totally mainstream.

So my answer is there's no simple explanation because there's no mature theory underlying the idea of a concatenative language. (As Einstein and Feynman said, if you can't explain your idea to a college freshman, you don't really understand it.) I'll go further and say although studying some of these languages, like Forth and PostScript, is an excellent use of time, trying to figure out exactly what people mean when they say "concatenative" is probably a waste of your time.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Norman Ramsey
  • 198,648
  • 61
  • 360
  • 533
  • Great answer. I'd never really thought that I might just not get it because there's not really a good explanation. :-) – Jason Baker May 27 '09 at 21:38
  • 1
    -1, while I agree that the terminology and the way that everyone is speaking about it is not very good, I boldly disagree that pursuing the idea is a waste of time. Sometimes it pays to learn languages that are different in structure and data manipulation technique to help our minds grow and discover new programming methods that may become helpful in certain situations. The fact that some people have a hard time talking about them doesn't make them a waste of time. – J. Polfer May 27 '09 at 22:02
  • 3
    I didn't say the languages were a waste of time. PostScript and FORTH are great things to study. I said it was a waste of time to try to figure out exactly what people mean when they say "concatenative". – Norman Ramsey May 27 '09 at 23:13
  • @Norman Ramsey - good point, didn't read it clearly enough. -1 withdrawn. – J. Polfer May 28 '09 at 17:59
  • There is indeed a real theory to a concantenative languages, its just so simple that most theorists don't care much about it, so there are no papers on it. See my answer below: http://stackoverflow.com/a/10422651/184528. – cdiggins May 22 '12 at 15:35
  • 3
    I hate seeing this as the accepted answer. It's wrong. Being concatenative is just having the property that _you can chop a part of it and it's a valid program, and join programs and get another program_. So simple it doesn't need much explaining, really. There are other things to concatenative programming languages, but that's the defining feature. – fede s. Aug 08 '16 at 20:52
  • I realize this is 8 years in. But this answer is downright *embarrassing*. The author has clearly made no attempt whatsoever to even vaguely engage with the literature out there on the subject. – junius Oct 09 '17 at 07:01
  • @Kevin what I could find, I tried to engage with---and failed. Perhaps you would be kind enough to cite the literature I overlooked? – Norman Ramsey Oct 09 '17 at 10:58
  • In May of 2009, the first line of that Wikipedia article on concatenative languages read: "A concatenative programming language is one in which all terms denote functions and the juxtaposition of terms denotes function composition." I think that would have been a decent place to start. [This article](http://www.kevinalbrecht.com/code/joy-mirror/j02maf.html) is literally entitled "The Mathematical Foundations of Joy." I don't see why someone would so cavalierly dismiss another researcher's work without, evidently, even taking the time to read what they have to say. – junius Oct 09 '17 at 19:53
  • Surely it seem categorically wrong to say there is no definition. There *are* definitions in use among the (small) community of concatenative programmers. Surely it seems wrong to dismiss what might be of interest based on an entirely subjective value judgement. I do not think that saying, in so many words: "this doesn't seem interesting to me, so don't bother with it" is especially instructive. It should be noted, incidentally, that the Okasaki paper you reference *cites von Thun's work on Joy*. – junius Oct 10 '17 at 01:50
  • Please define "mature theory". – Dmitri Zaitsev Sep 24 '19 at 15:04