aboutsummaryrefslogtreecommitdiff
path: root/Turing/Machine.hs
blob: 1eace5ece3d81c97db14914a73611cbc10844e73 (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
131
132
133
134
135
136
137
138
139
module Turing.Machine where

import Import

import qualified Data.Map.Strict as Map

import Data.List
import Data.Monoid
import Control.Monad

data Symbol = SymInit | SymWild | SymSpace | Symbol Char deriving (Eq, Ord)
instance Show Symbol where
    show (Symbol c) = [c]
    show SymInit    = ">"
    show SymWild    = "*"
    show SymSpace   = "_"

special :: Symbol -> Bool
special (Symbol _) = False
special _          = True

charToSym :: Char -> Symbol
charToSym '_' = SymSpace
charToSym c = Symbol c

data Action = W Symbol | L | R
instance Show Action where
    show (W sym) = show sym
    show L       = "←"
    show R       = "→"

type State = Int
type TransF = State -> Symbol -> Maybe (Action, State) -- TODO delete
type Trans = Map.Map (State,Symbol) (Action,State)

-- Turing Machine
data Machine = Machine { states  :: [State]
                       , s0      :: State
                       , finals  :: [State]
                       , symbols :: [Symbol]
                       , delta   :: TransF
                       , trans   :: Trans }
instance Show Machine where
    show (Machine sts ini fins syms _ trs) =
        intercalate "\n\n"
          [ "--- Turing Machine ---"
          , " States: [" ++ show (head sts) ++ ".." ++ show (last sts) ++ "]"
          , " Initial state: " ++ show ini
          , " Final states: " ++ show fins
          , " Symbols: " ++ show syms
          , " Transition table:\n" ++ showTrans trs ]
instance Monoid Machine where
    mempty  = nop
    mappend = comp

showTrans :: Trans -> String
showTrans trs = separator ++ intercalate' "\n" table ++ separator
    where separator = " +" ++ concatMap (\s -> replicate s '-' ++ "--+") lengths
          table = map (intercalate' " | "
                       . map (\ (ml, f) -> replicate (ml - length f) ' ' ++ f)
                       . zip lengths) fields
          lengths = map (maximum . map length) (transpose fields)
          fields = map (\ ((a, b), (c, d)) -> [show a, show b, show c, show d])
                   (Map.toList trs)
          intercalate' x xs = x ++ intercalate x xs ++ x

mkDelta :: Trans -> TransF
mkDelta trs st sym =
    msum $ map (`Map.lookup` trs) [(st, sym), (st, SymWild)]

mkMachine :: [(State, Symbol, Action, State)] -> Machine
mkMachine trs = Machine sts ini fins syms (mkDelta trns) trns
    where sts = sort $ union stsFrom stsTo
          ini = minimum sts
          fins = sort $ stsTo \\ stsFrom
          syms = nub . filter (not . special) . map (\(_,sy,_,_) -> sy) $ trs
          trns = Map.fromList (map (\(s1,sy,a,s2) -> ((s1,sy),(a,s2))) trs)
          stsTo = nub $ map (\(_,_,_,s) -> s) trs
          stsFrom = nub $ map (\(s,_,_,_) -> s) trs

nop :: Machine
nop = mkMachine [(0, SymWild, W SymWild, 1)]

freshen :: Machine -> Machine -> Machine
freshen m1 m2 = Machine sts ini fins syms d trns
    where sts = map (+ offset) (states m2)
          ini = s0 m2 + offset
          fins = map (+ offset) (finals m2)
          syms = symbols m2
          d = mkDelta trns
          trns = Map.map (\(a,s2) -> (a,s2+offset)) $
                    Map.mapKeys (\(s1,sy) -> (s1+offset,sy)) (trans m2)
          offset = maximum (states m1) + 1

comp :: Machine -> Machine -> Machine
comp m1 m2 = Machine sts ini fins syms d trns
    where sts = sort $ states m1 `union` states m2'
          ini = s0 m1
          fins = finals m2'
          syms = symbols m1 `union` symbols m2'
          d st sym = msum $ map (\ s -> Map.lookup (st,s) trns) [sym, SymWild]
          trns = Map.union connect $ Map.union (trans m1) (trans m2')
          connect = Map.fromList $
                    map (\ s1 -> ((s1,SymWild),(W SymWild, s0 m2'))) (finals m1)
          m2' = freshen m1 m2

-- Configuration
type Tape = [Symbol]

showTape :: Tape -> String
showTape = concatMap show

type Position = Int
data Config = Config { tape  :: Tape
                     , pos   :: Position
                     , state :: State }
instance Show Config where
    show (Config t p s) = concat [roof, "\n|", showTape t, "\n", pointer, "\n"]
        where roof = ' ' : replicate (length t) '_'
              pointer = replicate (p+1) ' ' ++ "▲" ++ show s

mkConfig :: Tape -> Config
mkConfig t = Config (SymInit:t) 1 0

step :: Config -> TransF -> Maybe Config
step (Config t p s) d = fmap doAction (d s (t !! p))
    where doAction (L, s') = Config (adjust t (p-1)) (p-1) s'
          doAction (R, s') = Config (adjust t (p+1)) (p+1) s'
          doAction (W sy, s')
              | sy == SymWild = Config t p s'
              | otherwise  = Config (adjust (replace t p sy) p) p s'
          adjust l newpos
              | diff > 0 = l ++ replicate diff SymSpace
              | diff < 0 && last l == SymSpace = init l
              | otherwise = l
              where diff = newpos - (length l - 1)
          replace [] _ _ = []
          replace (_:xs) 0 e = e : xs
          replace (x:xs) n e = x : replace xs (n-1) e