
Why Concatenative Programming Matters (2012) - azhenley
http://evincarofautumn.blogspot.com/2012/02/why-concatenative-programming-matters.html
======
tomxor
> A concatenative programming language is a point-free programming language in
> which all expressions denote functions and the juxtaposition of expressions
> denotes function composition. The combination of a compositional semantics
> with a syntax that mirrors such a semantics makes concatenative languages
> highly amenable to algebraic manipulation.

This is the reason i hate so many (not all) wikipedia articles - the
introduction is an exercise of code golf in human language.

This is devoid of the key quality most readers want from an encyclopedia
(understanding from an ignorant viewpoint), intros should not be a puzzle for
the reader which attempts to fit comprehensive technical description into a
single useless sentence.

~~~
bunderbunder
Lemme try in something closer to plain English:

In most programming languages, the way you compose functions is by creating
some other function that takes whatever arguments are necessary, applies the
first function to some subset of them, collects its result, and then applies
the second function to some other subset of the arguments, plus the result of
the first function.

IOW, while the syntax can be quite clean:

    
    
      let h(x) = f(g(x))
    

is doing quite a lot in the background. Moreso if some of the top-level
arguments are to be passed to f and not g:

    
    
      let h(x, y) = f(g(x), y)
    

In a concatenative language, all you have to do to compose functions is place
them one after the other. So those two compositions both become something more
like

    
    
      let h = g f
    
    

One big difference here, and the main part of how most concatenative languages
achieve this behavior, is that arguments are never stated or passed
explicitly. Instead, inputs and outputs are typically retrieved from and
placed onto some sort of stack.

(edit: Just realized never really said why they're called "concatenative".
It's because, at least in a Forth-style concatenative language where the
compiler isn't doing any fancy footwork, you can compose functions by
literally just concatenating them. So that `let h = g f` is basically saying,
"To execute H, first execute G and then immediately execute F.")

~~~
pointfree
Most languages that aim to be minimal bake in a minimal syntax, but without
implicit parameter passing, composability is not going to be extensible.

~~~
bunderbunder
In a forth-like language, you can think of all functions as implicitly being
unary: They take a stack, and return a stack.

I've never used any other kind of concatenative language, so I'm less able to
speak to them, but I'm guessing some similar situation applies for those as
well.

------
codr7
The truth is somewhere between Forth and Lisp if you ask me, I find dogmatic
Forth too primitive and Lisp too clever.

The language I'm currently working on [0], aims to find the sweet spot
starting from Lisp in Go.

[0] [https://github.com/codr7/g-fu](https://github.com/codr7/g-fu)

~~~
flavio81
>starting from Lisp in Go

Interesting. Please state what is the License of g-fu, so people can
contribute.

~~~
codr7
It's at the bottom of the readme, LGPL3; but I forgot the license file.

Thanks for bringing it to my attention.

------
tombert
About a year ago, I decided that I'm going to learn Postscript for no other
reason than to say that I know Postscript.

Coming from a functional background, the point-free nature of it wasn't too
confusing, and I actually grew to really enjoy it.

I never got too far into that quest largely because I didn't have much of a
practical need to be a Postscript expert, but it has since made me want to
learn Forth, which I have been pushing off for months now.

~~~
azhenley
I too recently got the itch to learn Forth. So I went _forth_ and implemented
a very simple interpreter for a small Forth dialect:
[https://github.com/AZHenley/goforth](https://github.com/AZHenley/goforth)

It was quite fun but I still can't say that I know much about actually using
Forth :)

~~~
JadeNB
> So I went and implemented a very simple interpreter for a small Forth
> dialect:

You can't just write that. Chuck Moore, I assert with no evidence whatsoever,
would require that you write "so I went _forth_ and implemented …."

~~~
azhenley
My apologies, I have corrected the mistake!

------
olodus
Oh awesome. I found concaternative languages when I was trying to learn Forth
last year. Forth was almost scary with how little syntax there is. Not even
Lisp really felt like that. Types felt a great thing to get a bit more
stability into it all. Really love how concat langs feel like a mid point of
performance - lisp - static types. Are still very new to them of course but
will continue to try to learn about them.

I found Kitten then too. Didn't realized until the end of the article that
this was it's creator. Really interesting post and glad to hear it might come
more. Magnet sounds really interesting. Will certainly check it out.

~~~
olodus
Aww... Totally missed it was from 2012...

------
azhenley
Discussion from 7 years ago:
[https://news.ycombinator.com/item?id=3582261](https://news.ycombinator.com/item?id=3582261)

Hopefully the state of concatenative programming has changed a little since
then?

------
crimsonalucard
In functional programming... Replace immuteable variables with no declared
variables. None.

Like the immuteability rule in functional programming, if you follow this rule
in any style of programming you will achieve concatenative programming.

~~~
binrec
It's technically possible to write in a concatenative style in a non-
concatenative language, but in most cases, it's nowhere near idiomatic. How
would you define a function that squares a number in a concatenative style in
Javascript?

Here's the best I can come up with:

    
    
      function compose(...funcs) {
        return stack => funcs.reduce((acc, cur) => cur(acc), stack)
      }
    
      function dup(stack) {
        stack.push(...[,,].fill(stack.pop()))
        return stack;
      }
    
      function mul(stack) {
        stack.push(stack.pop() * stack.pop())
        return stack;
      }
    
      const square = () => compose(dup, mul)
    
      console.log(square()([4]))
    

Then again, this could be a trick question someday - if the pipeline proposal
goes through, it'll be possible to write idiomatic concatenative Javascript.
(If you want to play with the pipeline operator, see here:
[https://defseg.io/etc/pipeline.html](https://defseg.io/etc/pipeline.html))
You'd still need to define all your functions as accepting a stack parameter,
but you wouldn't need a compose function, so you could do something like this:

    
    
      function dup(stack) {
        stack.push(...[,,].fill(stack.pop()))
        return stack;
      }
    
      function mul(stack) {
        stack.push(stack.pop() * stack.pop())
        return stack;
      }
    
      const square = stack => stack |> dup |> mul
    
      console.log([4] |> square)
      console.log([2] |> square |> square)
    

Now to write an ECMA proposal for recursive combinators... /s

~~~
crimsonalucard
This is actually completely incorrect. Concatenative still retains
immutability for parameters. It is a subset of functional programming.

You are using a stack which is not immutable.

A lot of javascript programmers think they are doing functional programming
but they don't get the essence of it. Yes you know map, yes you know reduce.
But you don't get it.

functional programming is in essence a mathematical function rather than a
procedural function. If you can fit your entire program into a single
expression or a single function without computational steps or procedures you
have achieved functional programming.

Immutability is a side effect of converting everything into a single
mathematical expression. Concatenative programming and functional programming
are the same thing as imperative programming BUT with more restrictions so of
course you can do concatenative programming in javascript AND you can be
idiomatic.

You are overcomplicating the concept. Literally:

    
    
      function square(x){
           return x*x
      }
    

is still concatenative.

all concatenative programming is, is using the compose operator to compose
your functions into a single function.

for the given:

    
    
      function a(x){
           return x*2
      }
    
      function b(x){
           return x*x
      }
    

if your goal is to compute (2x)^2

procedural is this:

    
    
      var y = 1;
      y = a(y);
      y = b(y);
      //literally a list of procedures mutating a value. Order matters. 
      console.log(y);
    
    

functional (without concatenative):

    
    
      const x = 1;
      const y = a(x);
      const z = b(y);
      console.log(z);
    

Above, the functions are applied on defined immutable variables. Order doesn't
matter as long as you keep all definitions the same. While order happens sort
of as a consequence to this, the concept for functional programming is to get
rid of procedures.

concatenative (still a valid functional program):

    
    
      const c = a |> b
      console.log(c(1));
    

In the above, a function application is only used here as the last step. The
IO step where functional AND concatenative programming breaks down, but
literally for concatenative programming your entire programming should be all
made up of function definitions and composed functions and no declared
variables and no applied functions. Just apply one function in the last step
for IO and your program is concatenative.

Javascript has been giving bootcampers completely wrong ideas about functional
programming and what it is. Learn a real functional programming lang to
actually get it. Haskell is a good one.

Also your examples literally defeat the purpose of functional and
concatenative programming. It makes the code worse. I would literally not
think concatenative programming or functional programming is better if I saw
that code for the first time. I would avoid functional programming like the
plague if it caused your code to blow up into a mess like that. I'm not here
to stretch my brain just to square a number.

~~~
binrec
>You are using a stack which is not immutable.

Yes, but that's beside the point. I said "style", not "paradigm". The basic
structure, not the totality of the thing. I don't know what CS researchers
would think of this distinction, but it seems convenient to have in practice.

You can use a functional style in Javascript without insisting on pure
immutability throughout your entire project, and there are advantages to being
able to do so. There are also advantages to being able to use a concatenative
style, which is why the pipeline operator was proposed.

It would be possible to rewrite that code to use an immutable stack, but for
the purpose of illustration - specifically, illustrating that there isn't
currently a good way to write in a concatenative style in Javascript - I don't
think it's necessary. You can use the style without the paradigm. (Besides,
the reference implementation of Joy mutates the underlying stack variable, and
if the way to get a concatenative paradigm in standards-compliant, runs-in-a-
browser Javascript is to Greenspun's Tenth Law a concatenative language...)

The better option would've been not to use a stack at all, and illustrate it
with integers, as you've done here. But you'd still need some way to manage
multiple variables to use a concatenative idiom to compute 2x^y.

>Also your examples literally defeat the purpose of functional and
concatenative programming. It makes the code worse.

Right. You _can_ follow the rules of the paradigm in Javascript, once you've
written enough of an interpreter for a concatenative language to let you do
so, but it'll make your code worse. But there are languages that are designed
for the paradigm - and in them, you can write good code that follows the rules
of it.

>Javascript has been giving bootcampers completely wrong ideas about
functional programming and what it is. Learn a real functional programming
lang to actually get it. Haskell is a good one.

Not a bootcamper - even worse, I work in a warehouse - but I might quit and
become one once my stock options vest...

~~~
crimsonalucard
>Yes, but that's beside the point. I said "style", not "paradigm". The basic
structure, not the totality of the thing. I don't know what CS researchers
would think of this distinction, but it seems convenient to have in practice.

CS researchers would say you don't know what you're talking about. Your
"style" actually made things worse. You can follow the paradigm IN javascript
and make your code more concise and better. Your points are true about writing
an interpreter but they are not applicable in the javascript case and most
cases as well. The CS term you are looking for is "Sugar". There is no sugar
in javascript for compose thus it it slightly more awkward to do functional or
concatenative programming in javascript than say haskell.

The pipeline operator is sugar for something that is close to compose...
However it is still very convenient to simply define a compose function even
without sugar for concatenative programming in javascript.

>You can use a functional style in Javascript without insisting on pure
immutability throughout your entire project

Functional programming IS immutable programming the two are one and the same.
Where it gets a little iffy is "pure" functional programming and "impure"
functional programming. That's usually just referring to IO. Again, you don't
know what you're talking about.

When you use the map or reduce you are not doing functional programming as a
paradigm nor as a style. You're simply using a function. Map exists in
functional programming as a higher order function, it also exists in
procedural programming as a higher order function because Map can be
implemented with a for loop which is a procedural primitive.

>The better option would've been not to use a stack at all, and illustrate it
with integers, as you've done here. But you'd still need some way to manage
multiple variables to use a concatenative idiom to compute 2x^y.

A stack isn't even relevant. You did nothing by introducing it except
introducing how to do things in a more complicated way.

Dual parameters are handled in lambda calculus through currying. It's even
easier in javascript as javascript supports recursion. Again you don't know
what you are talking about.

    
    
      function timesTwo(x){
           return x * 2;
      }
    
      function xToYPower(x){
           function result(y){
                return y === 0? 1 : x*result(y-1);
           }
           return result
      }
      
      // ex: 3^2 ===> xToYPower(3)(2)
     
      function compose2(g, h){
           return x => g(h(x));
      }
    
      const x = 3;
      const y = 5;
      console.log(compose2(times2, xToYPower(x))(y))
      //2*(3^5)
    
      // pipeline syntax shown below; 
      //my mistake in the earlier comment, I thought pipeline was the 
      // compose operator. It is not... it is actually the apply operator. Which with a 
      //little modification can be used as compose or similarly to compose. 
      
      console.log(y |> xToYPower(x) |> timesTwo);
    
    

See? Concatenative programming in javascript. And it's not less convenient.

Haskell is the idiomatic language for typed functional/concatenative
programming. This is what it looks like:

    
    
      timesTwo :: Int -> Int
      timesTwo x = 2 * x
    
      xToTheY :: Int -> Int -> Int
      xToTheY _ 0 = 1
      xToTheY x y = x * (xToTheY (y - 1))
    
      result = let x = 3
                   y = 5
                 in (timesTwo . (xToTheY x))(y)
      
      main = println result
    
      // - the "." is the compose operator. It is this operator that spawns the name
      //     "point free programming" and is the main "sugar" feature used for 
      //      concatenative programming
      // - haskell curries functions with multiple parameters automatically, hence 
      //      (xToTheY x) returns a function that that accepts y and will apply y to x 
      //      to get x^y. 
    
    
    

which is essentially the same thing just with more "sugar" but you can see
that it's not a huge step up from javascript.

> It would be possible to rewrite that code to use an immutable stack, but for
> the purpose of illustration - specifically, illustrating that there isn't
> currently a good way to write in a concatenative style in Javascript

There is a good way, like I just showed you above. It's not that far from
haskell which is THE definitive language for these styles of programming.

I'm not even an advocate for javascript. (TBH I ate the language). So you can
see here that what I'm saying is unbiased.

>Not a bootcamper - even worse, I work in a warehouse

Don't worry it's not worse. It's the same. Bootcamps literally teach you
everything you can get off the internet in a very superficial way. Anyone can
learn javascript bootcamp or not. Get better and get off javascript.

~~~
binrec
>Functional programming IS immutable programming the two are one and the same.

Yes, and many imperative languages allow you to use, in an idiomatic manner, a
functional style that avoids mutable state, even though these languages aren't
designed around the functional paradigm, and don't require you to adhere
purely, in the colloquial sense that means "strictly" or "completely" but has
fewer letters, to it. And the reason for this is that people have taken ideas
from languages that were designed to be functional rather than imperative.

If you want to bring up map and reduce, what's their genealogy? Did the
imperative world get the idea from ALGOL? Maybe they did, but I'd be
surprised.

>See? Concatenative programming in javascript. And it's not less convenient.

It still isn't great. To avoid stepping outside the paradigm, you have to be
willing to curry every function that needs multiple parameters. And I don't
know what that recursion is doing there - presumably I don't know what I'm
talking about again, but it seems to me that the entire body of `xToYPower`
could be replaced with `return y => x __y`.

~~~
crimsonalucard
>If you want to bring up map and reduce, what's their genealogy? Did the
imperative world get the idea from ALGOL? Maybe they did, but I'd be
surprised.

Genealogy is that it's a pattern from the functional world. It's usually
unused in procedural languages because they have special syntax for it like
the for loop. However there is no restriction to implement map using a for
loop. Therefore it is not part of the paradigm similar to how using functions
in a procedural language does not mean you are doing functional programming
from a stylistic perspective.

>To avoid stepping outside the paradigm, you have to be willing to curry every
function that needs multiple parameters

For compose yes you are correct, it has to be done.

>And I don't know what that recursion is doing there

The recursion is doing x^y. That is the meaning of the function name.

    
    
      2^3 = 8
      3^2 = 9
      xToY(2)(3) = 8
      xToY(3)(2) = 9
    

>but it seems to me that the entire body of `xToYPower` could be replaced with
`return y => x y`

x y with a space inbetween looks like a syntax error. I don't think it will
even run.

------
crimsonalucard
Another way to put it is a program with zero state or temporary state.

