The topic of State Machines is one of the most fascinating ever. It allows us to become better programmers by offering a simple but powerful way of thinking. It has always been (unfortunately) associated with compiler theory and is always learned in boring textbooks (and weird animals like dragons and tigers). This post provides a tangible example to understand the topic that can be followed by even a child. Promise.

Let us think of a machine having an infinitely long amount of tape.

The tape has symbols on it. It can be alphabets, it can be something else.

We have a head that can modify the values.

The head can move left

or right.

It can also erase and write new values.

The head can also read values.

You can also replace the head with you and a pencil at this point. You read the values, move the pencil and use it to modify values.

Using a piece of paper we can have instructions for the machine. For each scenario, we can think of what to do with the pencil when there is a particular symbol. What to do if there is a 1, what to do when there is a 0 or a blank, and where to move.

Let’s say we start at scenario one. Let’s execute the ifs. The 1 will become 0.

We then move to the left.

But then what? We are stuck. That’s why we also need to point out the next scenario so that we can get a continuous set of instructions.

Now we can get going and execute scenario 2 which leaves the value as is then moves to the left.

then scenario 5 and so on.

Replace scenario by state and that’s what states are.

It’s a bit much to write all those instructions. We can just translate it to a table as it’s already looking like we have some columns around.

If we don’t want our machine to run indefinitely, we can just replace a state in the path of execution with a halting instruction.

The above is essentially a turning machine. We have our indefinitely long tape, our finite set of symbols, head/pencil, finite states and rules to tell us how to run the machine.

If we can define a problem to be solved by a turing machine, then the problem is computable.

Expressing a turing machine in terms of state is a powerful concept. It allows us to translate our ideas better in terms of coding.

Code the above in Python. Think about how you will store the table, consume the tape etc.

tape = ['b','1', '1', '1', 'b']

instructions = {
    'state_1': {
        '1': {'write':'0', 'move':'left', 'go':'state_2'},
        '0': {'write':None, 'move':'right', 'go':'state_3'},
        'b': {'write':None, 'move':'left', 'go':'state_7'},
    },
    'state_2': {
        '1': {'write':None, 'move':'left', 'go':None},
        '0': {'write':None, 'move':'right', 'go':'state_4'},
        'b': {'write':None, 'move':'left', 'go':'state_8'},
    },
}

class Head:
    def __init__(self, index_on_tape):
        self.index_on_tape = index_on_tape
    
class Machine:
    def __init__(self, head, tape, instructions, starting_state):
        self.head = head
        self.tape = tape
        self.instructions = instructions
        self.current_index = self.head.index_on_tape
        self.current_state = starting_state
        
    def run(self):
        go_on = True
        
        while go_on:
            # read, write
            # move head
            # change state
            
            # read, write
            symbol_on_tape = self.tape[self.current_index]
            symbol_to_write = self.instructions[self.current_state][symbol_on_tape]['write']
            
            print(f'current state: {self.current_state}')
            print(f'symbol on tape:{symbol_on_tape} | symbol to write {symbol_to_write}')
            if symbol_to_write is None:
                pass
            else:
                self.tape[self.current_index] = symbol_to_write
                
            # move head
            move = self.instructions[self.current_state][symbol_on_tape]['move']
            if move == 'right':
                self.current_index += 1
                print('moving right')
            elif move == 'left':
                self.current_index -= 1
                print('moving left')
                
            # change state
            next_state = move = self.instructions[self.current_state][symbol_on_tape]['go']
            
            if next_state is None:
                print('halting!')
                go_on = False
            else:
                print(f'next state {next_state}')
                self.current_state = next_state 
            
        
head = Head(3)
machine = Machine(head, tape, instructions, 'state_1')
machine.run()

A first treatment of the topic in a fun way is found here. Badly wanted to code it up.

The code above treats each element as an object for making it conceptually easy to think about. The code can be improved by adding more machine methods and using a list to store the instructions.

Read More