The simplest model of a computer, adding one to a binary number, step by step.
turing.pl · output · proof · check · try it in the playground
In 1936 Alan Turing described an imaginary machine: a long tape of cells, a head that reads and writes one cell at a time and moves left or right, and a small table of instructions. Anything a modern computer can calculate, such a machine can calculate too.
Here the machine adds one to a binary number (written with only 0 and 1).
What is 101001 + 1? And can we watch every move of the machine?
start(add1, 0).
t([0, 0, 0, r], 0).
t([0, 1, 1, r], 0).
t([0, #, #, l], 1).
t([1, 0, 1, s], halt).
t([1, 1, 0, l], 1).
t([1, #, 1, s], halt).
Each line reads: in state S, seeing symbol X, write Y, move (l)eft,
(r)ight or (s)tay, and go to the next state. # is a blank cell.
State 0 runs right to the end of the number. State 1 walks back, turning 1s into 0s until it can turn a 0 (or a blank) into a 1: the carry.
find(State, Left, Cell, Right, OutTape) :-
t([State, Cell, Write, Move], Next),
move(Move, Left, Write, Right, A, B, C),
continue(Next, A, B, C, OutTape).
continue(halt, Left, Cell, Right, OutTape) :- reverse(Left, R), append(R, [Cell|Right], OutTape).
continue(State, Left, Cell, Right, OutTape) :- State \= halt, find(State, Left, Cell, Right, OutTape).
An interpreter is a program that runs another program. This one looks
up the instruction, moves the head, and repeats until the state is halt.
compute([1, 0, 1, 0, 0, 1], [1, 0, 1, 0, 1, 0, #]).
compute([1, 0, 1, 1, 1, 1], [1, 1, 0, 0, 0, 0, #]).
compute([1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, #]).
compute([], [1, #]).
In everyday numbers: 41 + 1 = 42, 47 + 1 = 48, 63 + 1 = 64 (the number
grows a digit), and an empty tape becomes 1. The trailing # is the blank
cell the head stopped next to.
For 101001, the proof records every move:
t([0, 1, 1, r], 0):
keep the 1, move right.Each move names the instruction it used and the tape before and after.
The checker went through all four runs: 144 steps.
halt”, “state 1 is not halt”)
were recomputed by the checker itself;Verdict: checked. All 144 steps verified, nothing taken on trust.
node bin/eyedia.js examples/turing.pl
node bin/eyedia.js --proof examples/turing.pl
Or open it in the playground.
Add true :+ compute([1, 0, 1, 1], _). and run again: you get
compute([1, 0, 1, 1], [1, 1, 0, 0, #])., that is 11 + 1 = 12.
A Turing machine is computation at its barest. With a proof, every tick of it becomes something you can read, replay and check.