Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

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.")




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


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.




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: