aboutsummaryrefslogtreecommitdiff
path: root/Readme.md
blob: 0eca67d8a866da870754c8726a87d24834a7ddd8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# CleanTuringMachines

Turing machines implementation in [Clean](http://wiki.clean.cs.ru.nl/Clean). Features include:

 * Straightforward types for turing machines and their states
 * Running and stepping a turing machine in execution
 * Simple `toString` instances for easy display of the types

Read further for examples.

### License

This program and the example are distributed under the MIT license. For more details, see the LICENSE file.

## Types and classes

### IterableClass

Provides two general classes:

    class step a :: a -> a
    class rewind a :: a -> a

Both are meant to be instantiated by types that can be 'stepped'. For example, the TuringMachineState instantiates the `step` class to be able to compute the next state for a current state. The `rewind` class is currently unused, but it only made sense to include it and make this a separate module. It allows a type to step backwards. Note, that for a Turing machine it is impossible to instantiate this class, because the transition function need not have an inverse.

There are three derivative functions:

    stepn :: Int a -> a | step a
    rewindn :: Int a -> a | rewind a
    stepOrRewindn :: Int a -> a | step, rewind a

The first and second simply iterate `step` and `rewind`. Negative values for the first argument will never terminate. The latter function will evaluate to either `rewindn` or `stepn`, depending on the sign of the first argument.

### TuringMachines

The tape is a simple list of Maybes of an arbitrary type. `Nothing` encodes a blank, `Just a` encodes the value `a`.

    :: Tape a :== [Maybe a]

The transition function (shown subsequently) results in a `TuringMachineMove`. This can either be a `Step`, or a `Halt`. Normally, the transition function is a partial function. Here, it is expected to be a nonpartial function to avoid runtime errors. What would normally be undefined is now `Halt`: it tells the turing machine to terminate.

    :: TuringMachineMove a = Step Int (Maybe a) Direction | Halt
    :: Direction = Left | Right

Here, `a` is the alphabet once again. A step changes state to the first argument, writes the second argument on the tape, and moves in the specified direction.

A Turing machine state consists of a Turing machine definition, but also includes the current state, the position of the tape head, the tape itself, and whether the machine is running or not:

    :: TuringMachineState a = { machine :: TuringMachine a,
                                state :: Int,
                                tapeHead :: Int,
                                tape :: Tape a,
                                running :: TuringMachineTermination }
    :: TuringMachineTermination = Running | Normal | Abnormal

Here, `a` is the tape alphabet and `i` is the input alphabet. We will come back to that.

As you can see, we specify states simply with integers. Mathematically, a Turing machine is a quintuple (Q,&Sigma;,&Gamma;,&delta;,q<sub>0</sub>) where Q is the set of states and q<sub>0</sub> the initial state (Sudkamp, Languages and Machines, 1997). Here, we take the integers as Q and 0 as q<sub>0</sub>. `a` relates to &Gamma;, `i` relates to &Sigma; and we will get back to &delta;.

The machine may be `Running`, or it may be terminated. In the latter case we distinguish between `Normal` termination (after a `Halt` move) and `Abnormal` termination (if the tape head position goes negative).

Finaly, the definition of the Turing machine itself:

    :: TuringMachine a = { alphabet :: [a],
                           inputs :: [a],
                           transition :: Int (Maybe a) -> TuringMachineMove a }

Again, we see the alphabet `a`. The transition function (&delta;) is a function from `Int` (the current state) and `Maybe a` (the character read by the tape head to a `TuringMachineMove a`. The `inputs` key specifies the input alphabet, typically a subset of the alphabet itself. It defines the characters allowed in the input.

### Examples

The following is a simple machine to replace `a` with `b` and vice versa. It is an example from Sudkamp, Languages and Machines, 1997, where it is represented as a state machine:

![A graphical representation of the replace machine](http://i.stack.imgur.com/gOtXY.png)

    replace :: TuringMachine Char Char
    replace = { alphabet = ['a','b'],
                inputs = ['a','b'],
                transition = f }
    where
        f :: Int (Maybe Char) -> TuringMachineMove Char
        f 0 Nothing     = Step 1 Nothing Right
        f 1 Nothing     = Step 2 Nothing Left
        f 1 (Just 'a')  = Step 1 (Just 'b') Right
        f 1 (Just 'b')  = Step 1 (Just 'a') Right
        f 2 (Just 'a')  = Step 2 (Just 'a') Left
        f 2 (Just 'b')  = Step 2 (Just 'b') Left
        f _ _           = Halt

Note the final catch-all alternative of the transition function `f`, which is used to make sure `f` is nonpartial.

## Firing up the machine

Getting a `TuringMachineState` from a `TuringMachine` is fairly straightforward. All you need is a `Tape`. For the example above, we may write:

    state :: TuringMachineState Char Char
    state = initTuringMachine replace tape
    where
        tape = [Just c \\ c <- fromString "aabbaa"]

The set builder for the tape is just ease of notation, we may as well have written `['a','a','b','b','a','b']`. A first and final blank is added to the tape by `initTuringMachine`.

`initTuringMachine` checks that there are no characters on the tape that are not in the input alphabet, and aborts if there are.

## Stepping and running

From this state we can either `step`...

    state1 = step state
    state5 = stepn 5 state

... or run until termination:

    statef = run state

## Showing results

The `TuringMachineState` instantiates `toString`. The result of `toString statef` would be:

    Normally terminated turing machine in state 2, tape head at 0.
    Tape: BbbaabbB

As you can see, the machine definition is in no way represented by this function.

Blanks (`Nothing` on the tape) are represented with 'B'.

## Future ideas

 * It would be really cool to have some kind of graphical frontend and a possibility to step through the machine with some input