Concatenative languages are languages where juxtaposition of functions represents composition. Programs consist of the primitives in the language combining to form a large function which takes program input as its argument and whose return value is written to output.
In many concatenative languages, all functions take and return the same structure so that the language can be implemented as a pipeline of operations on that structure. In the case that this structure is a stack, you get a model for many stack-based languages such as Joy, Underload, and CJam. For example, consider the following program that computes (n+1)2:
1 add dup mul
This is a composition of four different functions:
1
is a function that pushes1
to the top of the stack.add
is a function that replaces the top two items on the stack with their sum.dup
is a function that makes a copy of the top item on the stack and pushes it again.mul
is a function that replaces the top two items on the stack with their product.
We allow submissions in the form of functions. Usually, in CJam, I take this to mean a block like {1+_*}
. This is the example given in the linked answer, but with the concatenative interpretation, 1+_*
is a function, and {1+_*}
is a function that pushes a function to the stack.
In Python, if some function f
was a valid submission, lambda s:s[:-1]+[f(s[-1])]
would certainly not be. The latter seems to be what I've been doing for answers in concatenative languages.
My question, then, is that there are two viewpoints for this in a stack-based language:
- The theoretical viewpoint, in which juxtaposition of several functions composes them into a new function.
- The viewpoint of the implementation (which just applies each of the operations in sequence), in which the same juxtaposition of functions is a snippet that operates on some state already assumed to exist (the stack).
Which perspective is correct here?
1+_*
, but you can store{1+_*}
in a variable. \$\endgroup\$