Unlambda is an example of a Turing-complete programming language that implements your requirements.
- Unlambda has only one type, functions. They are also its only basic syntactic elements. In particular there are no variables.
- Its expressive power only requires two base terms,
s
, and k
. They would be your base $B$. k
takes two arguments and returns the first, while s
takes three arguments, and applies the result of applying the first one to the third one, to the result of applying the second one to the third one.
- It has an additional construct,
`
, which represents function application. It would be your binary operator $(\cdot)$. It is written in a prefix manner.
- So for any term
X
, Y
and Z
we have ``kXY = X
, and ```sXYZ = ``XZ`YZ
. These simple rules, believe it or not, are sufficient to make Unlambda Turing-complete.
- Unlambda has a few more built-ins but they are just here to make the programmer's life easier (although mentioning easy anywhere in the context of this language is probably an overstatement).
Natural numbers can be represented using Church's method, e.g. $3$ can be written as ``s``s`ksk``s``s`kski
(note i
, the identity, can be written as ``skk
). Pretty simple, no? Recursion can be defined by building a fixed point combinator, and from there the usual techniques can be applied to define more and more complex functions until an universal Turing machine has been simulated.
This language is based on SKI combinator calculus, which itself finds its source in Combinatory Logic. There is a simple mapping between the Lambda and SKI calculi, which luckily makes proving Turing completeness much easier than actually doing the work!
Of course,Now that I've really only talked about athe programming language, which is an abstract syntactic construct (even if I findlet's see how to interpret it more fun). To really answer your question, I should noteand whether or not this interpretation is easily computable. It turns out that there existsone can easily build a model of Unlambda in $C_M$ (Iexcepted its more complex operators, such as I/O extensions excepted). Indeed it is easy to build such a model from any model of the untyped lambda calculus by letting $[\![k]\!] = [\![(\lambda x.(\lambda y.x))]\!]$, $[\![s]\!] = [\![(\lambda x.(\lambda y.(\lambda z.(x z (yz))]\!]$, and $[\![`XY]\!] = [\![X]\!] [\![Y]\!]$.