So, I thought it would be a fun idea for my first ever Lisp/Scheme program to implement Alan Turing’s original a-machines from his paper, On Computable Numbers, with an Application to the Entscheidungsproblem (paper available to public). Fun? Oh, I hadn’t any idea…
Preamble; choice of implementation
I decided to go with the latest and greatest version of Scheme: R⁶RS. There are currently two implementations available under Ubuntu Linux: Ikarus and Ypsilon. I installed both so I wouldn’t be swayed by any tempting extensions to the standard. 🙂 Despite this, I ended up using Ikarus for most testing, as it ran quite a lot faster, although Ypsilon gave much better stack traces.
I also used the streams
library for dealing with infinite lists (SRFI 41), which is included with both implementations.
Note
I’ll be providing all the code so that you should be able to copy-paste it into a new file and run it.
The Machine
Turing sought to capture the essence of computation. For this purpose he constructed an idealized machine, which can read and write symbols to an infinitely long piece of tape. We are going to model these idealized machines and see what they can do.
First, we want some types to represent the a-machines (the a is for automatic). Each machine has a set of states (m-configurations) it can be in, each of which contains a mapping from a set of symbols to a list of actions and a new m-configuration. I decided that the state would be my basic unit of construction, but twiddled the meaning of m-configuration a tiny bit so that instead of having each configuration contain a mapping from symbols, I would instead have a list of configurations, each one with a list of which symbols activate it. I ended up with the following:
This defines a new record type called m-cfg
with the fields symbols
, operations
and next
. The define-record-type
form defines a constructor (make-m-cfg
) and accessors for each field (m-cfg-*
). Rather than have a ‘machine’ type, I decided that this would just be left implicit; if we know what the current state is then we can follow the links to next
whenever we want to.
The Tape
Now, each machine operates upon an infinitely long ‘tape’. To model this, I use two streams, which are infinite lists. One is the infinite length of the tape to the left of the machine, and the other is the infinite length of the tape to the right of the machine. I decided that the first item in the right list would be the current item that the machine is reading.
You will note that there are also the fields min
, max
, and index
. These are solely used to track how much of the tape the machine has “visited”. Without this information, we would not know how much of the tape to show when we want to look at it; and since it is infinitely long, this could be a problem! 🙂
Representing operations
The operations
that a machine can perform consist of:
- Move right
- Move left
- Print symbol
- Erase symbol
- Halt
I implemented these as an enumeration, just in case, but I didn’t actually end up utilizing any of the enumeration features.
There is a small difficulty with this representation: the ‘print’ operation needs to be able to take an argument. I decided that operations would always be passed around as lists, and that only ‘print’ would have a second element in the list: its argument. Here is a little shorthand to make this representation easier:
Thus, we can represent a list of operations like this: (list R R (P #\A) L E H)
—that’s right, right, print ‘A’ (Scheme’s syntax for characters is a little weird), left, erase, halt.
Moving around on the tape
Here is a simple tape; it is completely empty. Note that I use the symbol 'empty
to represent empty places on the tape. stream-constant
makes an infinite stream of the value(s) supplied.
Next we need code to actually implement the operations described above. It is fairly straightforward, but we also have to keep track of the index and max/min points on the tape:
Notice that erase is actually redundant because we can just print 'empty
. We also want a “dispatcher” of sorts that takes a value representing an operation and performs that operation. This is where passing the argument around with the ‘print’ came in useful:
Running the machine
Now that we have the operations implemented, we can almost run a state against a tape. First we need to figure out just which of the configurations of the state to run. This procedure receives a list of configurations (but they are all part of the same ‘state’) and a symbol, and picks the first configuration that has a matching symbol. Note that the configurations can also have the symbol 'any
, which matches anything.
Now that we have a way to find out which rule to perform, and how to perform it, we can run it against a tape. This procedure advances the machine to the next state, performing all the operations needed. It returns the new state and a new tape.
Displaying the tape
Being able to run the machine against a tape isn’t much good if we can’t see the result, so here’s a procedure to print out what it looks like. This is where we need the indexes we kept track of on the tape, so we know when to stop printing.
I print out a ‘.’ for each blank, and surround the current symbol with square brackets.
Turing Machines!
Now we can test it! Here is my definition of Turing’s first published machine:
Now you see why we needed to import ‘delay’… since Scheme is a strictly-evaluated language, we can’t just letrec
each state in terms of the others, so I wrap each one up in delay
, then force
it in one place; just before we use it in the run-machine
procedure.
Other than that it is fairly straightforward, each state has a list of m-configurations, each of which has a list of what symbols it accepts, the actions to take, and the next state to move to. After we letrec, we have the initial state defined as the ‘machine’—in this case, b
.
We can run this machine like so:
This gives us the following output:
[.]
0[.]
0.[.]
0.1[.]
0.1.[.]
0.1.0[.]
0.1.0.[.]
0.1.0.1[.]
0.1.0.1.[.]
0.1.0.1.0[.]
...
This looks correct: P0, R, R, P1, R, R, etc.
Machine redux
The next machine Turing gives is the same as the first one, only in a different form:
It has only one state, but changes depending on what the current symbol is. This produces the same output as the first machine, but in fewer steps:
[.]
[0]
0.[1]
0.1.[0]
0.1.0.[1]
0.1.0.1.[0]
0.1.0.1.0.[1]
0.1.0.1.0.1.[0]
0.1.0.1.0.1.0.[1]
0.1.0.1.0.1.0.1.[0]
...
You may be wondering why Turing leaves blanks between each printed symbol. He used the convention that only the ‘even’ squares (termed F-squares) would be the output. The ‘odd’ squares (termed E-squares) would be used as a scratch-pad.
The Third Machine
The third machine is a little more interesting. Whereas the first two printed out 01010101...
, this prints 01011011101111011111...
:
With the output (here I’ve used underlining to indicate the current symbol):
. ǝǝ0.0 ǝǝ0.0 ǝǝ0.0 ǝǝ0.0.. ǝǝ0.0.1 ǝǝ0.0.1 ǝǝ0.0.1 ǝǝ0.0.1 ǝǝ0.0.1 ǝǝ0.0.1 ǝǝ0.0.1.. ǝǝ0.0.1.0 ǝǝ0.0.1x0 ǝǝ0.0.1x0 ǝǝ0.0.1x0 ǝǝ0.0.1x0 ǝǝ0.0.1x0.. ǝǝ0.0.1x0.1 ǝǝ0.0.1x0.1 ǝǝ0.0.1.0.1 ǝǝ0.0.1.0.1 ǝǝ0.0.1.0.1.. ǝǝ0.0.1.0.1.1 ǝǝ0.0.1.0.1.1 ǝǝ0.0.1.0.1.1 ǝǝ0.0.1.0.1.1 ǝǝ0.0.1.0.1.1 ǝǝ0.0.1.0.1.1 ǝǝ0.0.1.0.1.1 ǝǝ0.0.1.0.1.1 ǝǝ0.0.1.0.1.1 ǝǝ0.0.1.0.1.1 ǝǝ0.0.1.0.1.1 ǝǝ0.0.1.0.1.1 ǝǝ0.0.1.0.1.1.. ǝǝ0.0.1.0.1.1.0 ǝǝ0.0.1.0.1.1x0 ǝǝ0.0.1.0.1x1x0 ǝǝ0.0.1.0.1x1x0 ǝǝ0.0.1.0.1x1x0 ǝǝ0.0.1.0.1x1x0 ǝǝ0.0.1.0.1x1x0 ǝǝ0.0.1.0.1x1x0.. ǝǝ0.0.1.0.1x1x0.1 ǝǝ0.0.1.0.1x1x0.1 ǝǝ0.0.1.0.1x1.0.1 ǝǝ0.0.1.0.1x1.0.1 ǝǝ0.0.1.0.1x1.0.1.. ǝǝ0.0.1.0.1x1.0.1.1 ǝǝ0.0.1.0.1x1.0.1.1 ǝǝ0.0.1.0.1x1.0.1.1 ǝǝ0.0.1.0.1x1.0.1.1 ǝǝ0.0.1.0.1.1.0.1.1 ǝǝ0.0.1.0.1.1.0.1.1 ǝǝ0.0.1.0.1.1.0.1.1 ǝǝ0.0.1.0.1.1.0.1.1 ǝǝ0.0.1.0.1.1.0.1.1.. ǝǝ0.0.1.0.1.1.0.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1.. ǝǝ0.0.1.0.1.1.0.1.1.1.0 ǝǝ0.0.1.0.1.1.0.1.1.1x0 ǝǝ0.0.1.0.1.1.0.1.1x1x0 ǝǝ0.0.1.0.1.1.0.1x1x1x0 ǝǝ0.0.1.0.1.1.0.1x1x1x0 ǝǝ0.0.1.0.1.1.0.1x1x1x0 ǝǝ0.0.1.0.1.1.0.1x1x1x0 ǝǝ0.0.1.0.1.1.0.1x1x1x0 ǝǝ0.0.1.0.1.1.0.1x1x1x0 ǝǝ0.0.1.0.1.1.0.1x1x1x0.. ǝǝ0.0.1.0.1.1.0.1x1x1x0.1 ǝǝ0.0.1.0.1.1.0.1x1x1x0.1 ǝǝ0.0.1.0.1.1.0.1x1x1.0.1 ǝǝ0.0.1.0.1.1.0.1x1x1.0.1 ǝǝ0.0.1.0.1.1.0.1x1x1.0.1.. ǝǝ0.0.1.0.1.1.0.1x1x1.0.1.1 ǝǝ0.0.1.0.1.1.0.1x1x1.0.1.1 ǝǝ0.0.1.0.1.1.0.1x1x1.0.1.1 ǝǝ0.0.1.0.1.1.0.1x1x1.0.1.1 ǝǝ0.0.1.0.1.1.0.1x1.1.0.1.1 ǝǝ0.0.1.0.1.1.0.1x1.1.0.1.1 ǝǝ0.0.1.0.1.1.0.1x1.1.0.1.1 ǝǝ0.0.1.0.1.1.0.1x1.1.0.1.1 ǝǝ0.0.1.0.1.1.0.1x1.1.0.1.1.. ǝǝ0.0.1.0.1.1.0.1x1.1.0.1.1.1 ǝǝ0.0.1.0.1.1.0.1x1.1.0.1.1.1 ǝǝ0.0.1.0.1.1.0.1x1.1.0.1.1.1 ǝǝ0.0.1.0.1.1.0.1x1.1.0.1.1.1 ǝǝ0.0.1.0.1.1.0.1x1.1.0.1.1.1 ǝǝ0.0.1.0.1.1.0.1x1.1.0.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1.0.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1.0.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1.0.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1.0.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1.0.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1.0.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1.0.1.1.1.. ǝǝ0.0.1.0.1.1.0.1.1.1.0.1.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1.0.1.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1.0.1.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1.0.1.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1.0.1.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1.0.1.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1.0.1.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1.0.1.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1.0.1.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1.0.1.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1.0.1.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1.0.1.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1.0.1.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1.0.1.1.1.1 ǝǝ0.0.1.0.1.1.0.1.1.1.0.1.1.1.1
Here we can see the scratch-pad being used. We can also see the beginnings of a pattern of execution; notice how the machine returns to the beginning of the tape after completing each set of 1
s.
Opus Magnum
Next up was my main challenge. One of the major contributions of Turing’s paper was to display a machine which could emulate any other machine you wanted. In essence, you don’t actually need lots of different machines. You can just build one, and it can do anything any of the other machines can do! This is the principle behind modern general-purpose computers.
This is a very big, and complex machine. Some of the intricacies not involved in the other machines are:
- m-functions; that is, configurations which accept parameters—luckily, this was surprisingly easy to implement using Scheme; I simply wrap the
delay
ed code inside another lambda - m-configurations which are parametrized over all symbols on the machine—this is solved by just
map
ping a lambda over the list of symbols - variadic m-functions—solved by the magic of
case-lambda
- poorly-scanned journal document containing Fraktur and Greek letters
But not only was this by far the biggest and most complex machine supplied by Turing, I had read texts mentioning unspecified bugs in the program.
… and sure enough, I ran into a ‘bug’. There were some configurations used in the machine which weren’t defined in the paper! At first I thought this was due to the low resolution of the PDF, but even enhancing the image didn’t help.
After much supplication and burnt offerings to the God of the Internet, I managed to find that:
Someone else did the work already
Yay!
More specifically, I found a paper entitled Understanding Turing’s Universal Machine — Personal Style in Program Description (which is unfortunately not available to the public), a marvelous paper that not only explains the errors made in detail, but also provides a nice, corrected version of Turing’s exposition of his machine.
After painstakingly re-checking all the states again, I arrived at this:
I don’t think I can blame Turing much for the errors in the paper. It seems as though some arose through printing typos, and attempting to debug this baroque machine by hand, on paper, would have been a difficult task. (I don’t think he even had Visual Studio!)
A machine in a machine
Of course, the final test of this is to see whether this machine can actually emulate another like it is supposed to. I defined a short procedure to set up a machine on a tape according to Turing’s ingenious encoding.
A quick explanation of Turing’s encoding
The idea is to first simplify, then encode the states. Turing noted that many of the m-configurations’ operations could be considered redundant:
- as mentioned above, instead of having “erase” we can simply print the ‘blank’ symbol
- instead of not modifying the symbol, we simply print the symbol already present
There are then only three types of operation each state needs to perform:
- print something and go left
- print something and go right
- print something and stay put
States which have a sequence of operations can be split into a series of states, each of which transfers control to the next one.
Now, if we encode all the symbols and configurations as numbers, we can write them out. Turing chose to encode them via this scheme:
- configurations’ numbers are the symbol ‘D’ followed by n ‘A’s, where n is the number of the state
- symbols’ numbers are similar, with ‘D’ followed by n ‘C’s. (Turing set ‘blank’ to always be symbol 0, represented as simply “D”)
So to encode each configuration, we write down its number, the symbol it accepts, the symbol it outputs, which direction to move, and which state to go to next. We prefix each configuration with ‘;’. (When we input it into the machine we also sandwich the whole thing between ‘ǝǝ’ and ‘∷’.)
Here is the example which Turing gives in his paper. I have formatted it to make it easier to read. Can you tell what it does?
If we translate the symbols to get numbers we have the following:
This machine prints alternately 0.1.0.1.
. In fact, when I first typed it up, I left off an ‘A’ on the 3rd state and couldn’t figure out why the machine was printing 0.11111...
!
Just to show it works
Here is some output of the universal machine running the ‘0101′ machine. I have only included a snippet as the machine takes a while to get to this stage. You’ll also notice the output format is different from the other machines; this one outputs some state information and the output of the emulated machine (in this case, 0 and 1), separated by colons. So far, after a minute or so, the machine has output 010
😀
.ǝǝ;.D.A.D.DuCuR.DyAyAy;.D.A.A.D.D.R.D.A.A.A.;.D.A.A.A.D.D.C.C.R.D.A.A.A.A.;.D.A.A.A.A.D.D.R.D.A.∷.:.D.A.D.:.0.:.D.C.D.A.A.D.:.D.C.D.D.A.A.A.D.:.1.:.D.C.D.D.C.C.D.A.A.A.A.D.:.D.CvDvDvCvCvDxD.A.D.:.0.:.D.C .ǝǝ;.D.A.D.DuCuR.DyAyAy;.D.A.A.D.D.R.D.A.A.A.;.D.A.A.A.D.D.C.C.R.D.A.A.A.A.;.D.A.A.A.A.D.D.R.D.A.∷.:.D.A.D.:.0.:.D.C.D.A.A.D.:.D.C.D.D.A.A.A.D.:.1.:.D.C.D.D.C.C.D.A.A.A.A.D.:.D.CvDvDvCvCvDxD.A.D.:.0.:.D.C .ǝǝ;.D.A.D.DuCuR.DyAyAy;.D.A.A.D.D.R.D.A.A.A.;.D.A.A.A.D.D.C.C.R.D.A.A.A.A.;.D.A.A.A.A.D.D.R.D.A.∷.:.D.A.D.:.0.:.D.C.D.A.A.D.:.D.C.D.D.A.A.A.D.:.1.:.D.C.D.D.C.C.D.A.A.A.A.D.:.D.CvDvDvCvCvDxD.A.D.:.0.:.D.C .ǝǝ;.D.A.D.DuCuR.DyAyAy;.D.A.A.D.D.R.D.A.A.A.;.D.A.A.A.D.D.C.C.R.D.A.A.A.A.;.D.A.A.A.A.D.D.R.D.A.∷.:.D.A.D.:.0.:.D.C.D.A.A.D.:.D.C.D.D.A.A.A.D.:.1.:.D.C.D.D.C.C.D.A.A.A.A.D.:.D.CvDvDvCvCvDxD.A.D.:.0.:.D.C .ǝǝ;.D.A.D.DuCuR.DyAyAy;.D.A.A.D.D.R.D.A.A.A.;.D.A.A.A.D.D.C.C.R.D.A.A.A.A.;.D.A.A.A.A.D.D.R.D.A.∷.:.D.A.D.:.0.:.D.C.D.A.A.D.:.D.C.D.D.A.A.A.D.:.1.:.D.C.D.D.C.C.D.A.A.A.A.D.:.D.CvDvDvCvCvDxD.A.D.:.0.:.D.C .ǝǝ;.D.A.D.DuCuR.DyAyAy;.D.A.A.D.D.R.D.A.A.A.;.D.A.A.A.D.D.C.C.R.D.A.A.A.A.;.D.A.A.A.A.D.D.R.D.A.∷.:.D.A.D.:.0.:.D.C.D.A.A.D.:.D.C.D.D.A.A.A.D.:.1.:.D.C.D.D.C.C.D.A.A.A.A.D.:.D.CvDvDvCvCvDxD.A.D.:.0.:.D.C .ǝǝ;.D.A.D.DuCuR.DyAyAy;.D.A.A.D.D.R.D.A.A.A.;.D.A.A.A.D.D.C.C.R.D.A.A.A.A.;.D.A.A.A.A.D.D.R.D.A.∷.:.D.A.D.:.0.:.D.C.D.A.A.D.:.D.C.D.D.A.A.A.D.:.1.:.D.C.D.D.C.C.D.A.A.A.A.D.:.D.CvDvDvCvCvDxD.A.D.:.0.:.D.C .ǝǝ;.D.A.D.DuCuR.DyAyAy;.D.A.A.D.D.R.D.A.A.A.;.D.A.A.A.D.D.C.C.R.D.A.A.A.A.;.D.A.A.A.A.D.D.R.D.A.∷.:.D.A.D.:.0.:.D.C.D.A.A.D.:.D.C.D.D.A.A.A.D.:.1.:.D.C.D.D.C.C.D.A.A.A.A.D.:.D.CvDvDvCvCvDxD.A.D.:.0.:.D.C .ǝǝ;.D.A.D.DuCuR.DyAyAy;.D.A.A.D.D.R.D.A.A.A.;.D.A.A.A.D.D.C.C.R.D.A.A.A.A.;.D.A.A.A.A.D.D.R.D.A.∷.:.D.A.D.:.0.:.D.C.D.A.A.D.:.D.C.D.D.A.A.A.D.:.1.:.D.C.D.D.C.C.D.A.A.A.A.D.:.D.CvDvDvCvCvDxD.A.D.:.0.:.D.C .ǝǝ;.D.A.D.DuCuR.DyAyAy;.D.A.A.D.D.R.D.A.A.A.;.D.A.A.A.D.D.C.C.R.D.A.A.A.A.;.D.A.A.A.A.D.D.R.D.A.∷.:.D.A.D.:.0.:.D.C.D.A.A.D.:.D.C.D.D.A.A.A.D.:.1.:.D.C.D.D.C.C.D.A.A.A.A.D.:.D.CvDvDvCvCvDxD.A.D.:.0.:.D.C .ǝǝ;.D.A.D.DuCuR.DyAyAy;.D.A.A.D.D.R.D.A.A.A.;.D.A.A.A.D.D.C.C.R.D.A.A.A.A.;.D.A.A.A.A.D.D.R.D.A.∷.:.D.A.D.:.0.:.D.C.D.A.A.D.:.D.C.D.D.A.A.A.D.:.1.:.D.C.D.D.C.C.D.A.A.A.A.D.:.D.CvDvDvCvCvDxD.A.D.:.0.:.D.C .ǝǝ;.D.A.D.DuCuR.DyAyAy;.D.A.A.D.D.R.D.A.A.A.;.D.A.A.A.D.D.C.C.R.D.A.A.A.A.;.D.A.A.A.A.D.D.R.D.A.∷.:.D.A.D.:.0.:.D.C.D.A.A.D.:.D.C.D.D.A.A.A.D.:.1.:.D.C.D.D.C.C.D.A.A.A.A.D.:.D.CvDvDvCvCvDxD.A.D.:.0.:.D.C .ǝǝ;.D.A.D.DuCuR.DyAyAy;.D.A.A.D.D.R.D.A.A.A.;.D.A.A.A.D.D.C.C.R.D.A.A.A.A.;.D.A.A.A.A.D.D.R.D.A.∷.:.D.A.D.:.0.:.D.C.D.A.A.D.:.D.C.D.D.A.A.A.D.:.1.:.D.C.D.D.C.C.D.A.A.A.A.D.:.D.CvDvDvCvCvDxD.A.D.:.0.:.D.C .ǝǝ;.D.A.D.DuCuR.DyAyAy;.D.A.A.D.D.R.D.A.A.A.;.D.A.A.A.D.D.C.C.R.D.A.A.A.A.;.D.A.A.A.A.D.D.R.D.A.∷.:.D.A.D.:.0.:.D.C.D.A.A.D.:.D.C.D.D.A.A.A.D.:.1.:.D.C.D.D.C.C.D.A.A.A.A.D.:.D.CvDvDvCvCvDxD.A.D.:.0.:.D.C .ǝǝ;.D.A.D.DuCuR.DyAyAy;.D.A.A.D.D.R.D.A.A.A.;.D.A.A.A.D.D.C.C.R.D.A.A.A.A.;.D.A.A.A.A.D.D.R.D.A.∷.:.D.A.D.:.0.:.D.C.D.A.A.D.:.D.C.D.D.A.A.A.D.:.1.:.D.C.D.D.C.C.D.A.A.A.A.D.:.D.CvDvDvCvCvDxD.A.D.:.0.:.D.C .ǝǝ;.D.A.D.DuCuR.DyAyAy;.D.A.A.D.D.R.D.A.A.A.;.D.A.A.A.D.D.C.C.R.D.A.A.A.A.;.D.A.A.A.A.D.D.R.D.A.∷.:.D.A.D.:.0.:.D.C.D.A.A.D.:.D.C.D.D.A.A.A.D.:.1.:.D.C.D.D.C.C.D.A.A.A.A.D.:.D.CvDvDvCvCvDxD.A.D.:.0.:.D.C .ǝǝ;.D.A.D.DuCuR.DyAyAy;.D.A.A.D.D.R.D.A.A.A.;.D.A.A.A.D.D.C.C.R.D.A.A.A.A.;.D.A.A.A.A.D.D.R.D.A.∷.:.D.A.D.:.0.:.D.C.D.A.A.D.:.D.C.D.D.A.A.A.D.:.1.:.D.C.D.D.C.C.D.A.A.A.A.D.:.D.CvDvDvCvCvDxD.A.D.:.0.:.D.C .ǝǝ;.D.A.D.DuCuR.DyAyAy;.D.A.A.D.D.R.D.A.A.A.;.D.A.A.A.D.D.C.C.R.D.A.A.A.A.;.D.A.A.A.A.D.D.R.D.A.∷.:.D.A.D.:.0.:.D.C.D.A.A.D.:.D.C.D.D.A.A.A.D.:.1.:.D.C.D.D.C.C.D.A.A.A.A.D.:.D.CvDvDvCvCvDxD.A.D.:.0.:.D.C .ǝǝ;.D.A.D.DuCuR.DyAyAy;.D.A.A.D.D.R.D.A.A.A.;.D.A.A.A.D.D.C.C.R.D.A.A.A.A.;.D.A.A.A.A.D.D.R.D.A.∷.:.D.A.D.:.0.:.D.C.D.A.A.D.:.D.C.D.D.A.A.A.D.:.1.:.D.C.D.D.C.C.D.A.A.A.A.D.:.D.CvDvDvCvCvDxD.A.D.:.0.:.D.C .ǝǝ;.D.A.D.DuCuR.DyAyAy;.D.A.A.D.D.R.D.A.A.A.;.D.A.A.A.D.D.C.C.R.D.A.A.A.A.;.D.A.A.A.A.D.D.R.D.A.∷.:.D.A.D.:.0.:.D.C.D.A.A.D.:.D.C.D.D.A.A.A.D.:.1.:.D.C.D.D.C.C.D.A.A.A.A.D.:.D.CvDvDvCvCvDxD.A.D.:.0.:.D.C .ǝǝ;.D.A.D.DuCuR.DyAyAy;.D.A.A.D.D.R.D.A.A.A.;.D.A.A.A.D.D.C.C.R.D.A.A.A.A.;.D.A.A.A.A.D.D.R.D.A.∷.:.D.A.D.:.0.:.D.C.D.A.A.D.:.D.C.D.D.A.A.A.D.:.1.:.D.C.D.D.C.C.D.A.A.A.A.D.:.D.CvDvDvCvCvDxD.A.D.:.0.:.D.C
And that’s enough for today! Feel free to post corrections, additions, your own Turing machines, and so on 🙂