-- SPDX-FileCopyrightText: Chris Pressey, the creator of this work, has dedicated it to the public domain. -- For more information, please refer to -- SPDX-License-Identifier: Unlicense module Language.Turmac.Model where import Data.Char (isSpace) type StateId = String type Symbol = String type Direction = Int type TMRule = (StateId, Symbol, Symbol, StateId, Direction) start = "S0" blank = "_" -- | Represents the infinite tape of the Turing machine -- For efficiency, we only store cells that we have visited, and that are -- not blank (unless they are still needed because they appear between -- non-blank cells that we have visited). data Tape = Tape { leftCells :: [Symbol] -- Cells to the left of head (reversed) , currentCell :: Symbol -- Cell under head , rightCells :: [Symbol] -- Cells to the right of head } deriving (Eq) instance Show Tape where show t = "[" ++ (showTape $ getTapeContents t) ++ "]" -- | Helper functions for tape visualization showTape [] = "" showTape [sym] = sym showTape (sym:rest) = sym ++ "," ++ showTape rest stripLeftBlanks :: [Symbol] -> [Symbol] stripLeftBlanks tape@(cell:rest) = if cell == blank then stripLeftBlanks rest else tape stripLeftBlanks other = other stripRightBlanks :: [Symbol] -> [Symbol] stripRightBlanks = reverse . stripLeftBlanks . reverse getTapeContents :: Tape -> [Symbol] getTapeContents Tape{ leftCells=lc, currentCell=cc, rightCells=rc } = stripLeftBlanks (reverse lc) ++ [cc] ++ stripRightBlanks rc -- | A configuration is the complete instantaneous state of the TM data Configuration = Configuration { tmTape :: Tape , tmPos :: Integer -- position of tape head relative to start , tmState :: StateId -- this could be a halt state } deriving (Eq) instance Show Configuration where show c = "State: " ++ (tmState c) ++ ", Tape: " ++ show (tmTape c) isHaltState ('@':_) = True isHaltState _ = False isHalted (Configuration _ _ state) = isHaltState state -- | Initialize an empty tape with all zeros emptyTape :: Tape emptyTape = Tape [] blank [] -- | Initialize a tape with given input symbols initTape :: [Symbol] -> Tape initTape [] = emptyTape initTape (x:xs) = Tape [] x xs -- | Move tape head left moveLeft :: Tape -> Tape moveLeft (Tape (l:ls) c rs) = Tape ls l (c:rs) moveLeft (Tape [] c rs) = Tape [] blank (c:rs) -- Extend with zero -- | Move tape head right moveRight :: Tape -> Tape moveRight (Tape ls c (r:rs)) = Tape (c:ls) r rs moveRight (Tape ls c []) = Tape (c:ls) blank [] -- Extend with zero -- | Write symbol at current position writeSymbol :: Symbol -> Tape -> Tape writeSymbol sym (Tape ls _ rs) = Tape ls sym rs -- | Read current symbol readSymbol :: Tape -> Symbol readSymbol = currentCell -- | Initialize TM state with empty tape initConfiguration :: Configuration initConfiguration = Configuration emptyTape 0 start -- | Initialize TM state with input initConfigurationWithInput :: [Symbol] -> Configuration initConfigurationWithInput input = Configuration (initTape input) 0 start