Concatenative programming
This page is a work in progress. Here be dragons.
Most programming languages are applicative, where things are evaluated by applying functions to arguments.
In concatenative programming languages, things are evaluated by composing functions together, all operating on a shared data structure (commonly a stack) passed around from function to function, and composition is expressed as the concatenation of programs.
My favorite example of concatenative programming is Slava Pestov’s implementation of finding the roots of a quadratic equation in Factor:
! Copyright (C) 2007 Slava Pestov.
! See https://factorcode.org/license.txt for BSD license.
USING: kernel math math.functions ;
IN: math.quadratic
: monic ( c b a -- c' b' ) [ / ] curry bi@ ;
: discriminant ( c b -- b d ) [ nip ] [ sq 4 / swap - sqrt ] 2bi ;
: critical ( b d -- -b/2 d ) [ -2 / ] dip ;
: +- ( x y -- x+y x-y ) [ + ] [ - ] 2bi ;
: quadratic ( c b a -- alpha beta )
monic discriminant critical +- ;
:: qeval ( x c b a -- y )
c b x * + a x sq * + ;
This code makes good use of combinators, concise word definitions, and above all, it’s elegant.
For example, monic converts an equation into its monic equivalent by using the bi@ combinator to execute the quotation created by [ / ] curry with both values and .
The fact that this can be expressed with only three words total is amazing to me, and is why I’m so drawn to concatenative programming.