Malbolge Unshackled is a dialect of Malbolge from 2007 by Ørjan Johansen. It attempts to remove the arbitrary memory limits of Malbolge in order to create a language that is hopefully Turing complete, while keeping closely to the spirit of Malbolge in most ways.
Changes from Malbolge
The following describes how Malbolge Unshackled deviates from Malbolge, as well as some rationale for the changes.
The values and addresses of cells in Malbolge Unshackled have an unbounded number of trits. This immediately presents a problem with the crazy operation, because op(0,0) is 1, not 0, and so it is not possible to pad values with zeros and expect the value of the tritwise operator to be the same integer.
This is solved by letting the allowable values be a subset of the 3-adic integers. In Malbolge Unshackled the first trit of a value is considered to repeat indefinitely to the left. So ...01 = ...001 = ...00001. The result of op(...01,...01) is then ...10 = ...110 = ...11110. Values beginning with 0 may be identified with the natural numbers, as is done during I/O and instruction decoding.
The width of a value is the number of trits other than the initial repeating ones.
Instruction execution depends on calculating remainders modulo 94. The question then is how to do this for values that are not natural numbers. The mathematical ideal would be an operation that is additive, but this is not possible:
...111 + ...111 + ...001 = ...000,
but there is no integer n such that n+n+1 is 0 (mod 94).
Malbolge Unshackled instead lets ...111 and ...222 have the same results with modulo operations as the corresponding 10-trit values, and other values starting with the same trits are calculated as offsets from these. For example,
...1102 mod 94 = (...1111 - 2) mod 94 = (11111111113 - 2) mod 94 = (29524-2) mod 94 = 6.
In Malbolge, the memory after the program is filled by an iterative procedure, which repeats the values every 6 cells. Since this iteration can never reach addresses not starting with 0, Malbolge Unshackled continues the filling of these cells by generalizing the pattern and using remainders modulo 6.
The tritwise rotation operation * presents special problems. Once the number of trits becomes unbounded, it is not clear what should happen with the trit that is shifted off to the right. One might try either to drop it altogether or to put it in a fixed position.
Unfortunately neither of these works, because the rotation operation is the only way to create usable values that are larger in size than those we start with, and this happens by the back rotation of the final trit. So either of these would mean an absolute limit on the size of values produced by the program.
Instead, Malbolge Unshackled lets the width of rotation be a variable, which grows with the values in the D register. The growth is fairly unpredictable (and implementation dependent), but not entirely:
- The rotation width starts as at least 10 trits.
- If a j operation increases the width of the D register to more than half the rotation width, then the rotation width changes to correct this.
- As long as the D register does not increase width beyond the previous maximum, the rotation width does not change.
- It is unspecified whether the auto-increment of the D register can register a width change.
Malbolge Unshackled does not do I/O modulo 256 but considers values starting with 0 to be Unicode characters. Values starting with trits 1 and 2 are reserved for further expansion, so far only the following are used:
...22 represents the end of file ...21 represents the end of line character (automatically converted on I/O)
While the language is intended to keep the spirit of Malbolge, backwards compatibility is a harder matter. Initial reports that the Malbolge cat program was working turned out to be due to an interpreter bug that caused the rotation width to stay at the Malbolge default of 10.
However, it does not seem impossible to make shorter programs that work in both Malbolge and in Malbolge Unshackled. I would intuitively suggest the following principles:
- Avoid the * operation unless you are sure that the first and last trits of [D] are identical.
- Use exact values on I/O.
- Accept both \10 and ...21 as newline on input, for freshly produced newlines use the Malbolge \10 convention on output (may not work on Macs).
- Avoid programs longer than 1/3 of memory.
- Avoid wrapping across memory thirds.