\$\begingroup\$

The goal of this challenge is to (eventually) output every possible halting program in a language of your choice. At first this may sound impossible, but you can accomplish this with a very careful choice of execution order.

Below is an ASCII diagram to illustrate this. Let the columns represent a numbering of every possible program (each program is a finite number of symbols from a finite alphabet). Let each row represent a singular step in execution of that program. An X represent the execution performed by that program at that time-step.

step# p1 p2 p3 p4 p5 p6 1 X X X X X X 2 X X X X X 3 X X X X 4 X X X X 5 X X X 6 X X 7 X X 8 X X 9 X X ∞ X X

As you can tell, programs 2 and 4 don't halt. If you were to execute them one-at-a-time, your controller would get stuck in the infinite loop that is program 2 and never output programs 3 and beyond.

Instead, you use a dovetailing approach. The letters represent a possible order of execution for the first 26 steps. The * s are places where that program has halted and is outputted. The . s are steps that haven't been executed yet.

step# p1 p2 p3 p4 p5 p6 1 A C F J N R V 2 B E I M Q * Z 3 D H * P U 4 G L T Y 5 K O X 6 * S . 7 W . 8 . . 9 . . ∞ . .

Requirements for the target language

The target language (the one being parallel-interpreted) must be Turing-complete. Other than that, it can be any language that's Turing-complete, including Turing-complete subsets of much larger languages. You are also free to interpret things like cyclic tag system rules. You are also allowed to create a language to test, as long as you can show why it is Turing-complete.

As an example, if you choose to test brainfuck, then it is best to test just the []-+<> subset, since input is not supported and output is just thrown away (see below).

When it comes to the "controller" program (which you are golfing), there's no special requirements. Normal language restrictions apply.

How to create an infinite list of programs

The majority of programming languages can be represented as a series of symbols from a finite alphabet. In this case, it is relatively easy to enumerate a list of every possible program in order of increasing length. The alphabet you use should be representative of the requirements of the target language. In most cases, this is printable ASCII. If your language supports Unicode as an additional feature, you should not test every possible combination of Unicode characters, just ASCII. If your language only uses []-+<> then don't test out the various combinations of "comment" ASCII characters. Languages like APL would have their own special alphabets.

If your language is best described in some non-alphabetic way, like Fractran or Turing Machines, then there are other equally valid methods of generating a list of all possible valid programs.

Interpreting an ever-growing list of programs

The key part of this challenge is to write a parallel interpreter for a growing list of programs. There are some basic steps for this:

Add a finite number of programs to the list

Interpret each program on the list individually for a finite period of time. This can be accomplished by performing one instruction step for each. Save all of the states.

Remove all terminating/error-throwing programs from the list

Output the cleanly halted* programs

Add some more programs to the list

Simulate each program in turn, picking up execution of older programs where it left off

Remove all terminating/error-throwing programs from the list

Output the cleanly halted* programs

repeat

*You should only output programs that halt cleanly. This means that there were no syntax errors or uncaught exceptions thrown during execution. Programs which ask for input should also be terminated without outputting them. If a program produces output, you shouldn't terminate it, just throw the output away.

More rules