implementation module tm

import	StdArray, StdBool, StdChar, StdInt, StdList, StdString

::	TmState
	=	{	turing		:: !Turing
		,	transition	:: !TrNr
		,	command		:: !Comm
		}
::	Turing
	=	{	transitions	:: ![Transition]
		,	tape		:: !Tape
		,	state		:: !State
		}
::	Transition
	=	{	start		:: !State
		,	sigma		:: !Head
		,	end			:: !State
		,	move		:: !Char
		}
::	Tape
	=	{	content		:: !String
		,	head		:: !Int
		}
::	State	:== String
::	Head	:== Char
::	TrNr	:== Int
::	Comm	=	Erase | None | MoveR1 | MoveR | MoveL | Halt | ErrorL | ErrorT
			|	Write Char


//	Perform one step of a Turing machine.
Step :: !TmState -> TmState
Step {turing}
	= {turing={turing & tape=newtape,state=newstate},transition=transition_nr,command=newcommand}
where
	tape							= turing.tape
	head							= tape.content.[tape.head]
	(transition_nr,transition)		= SelectTransition 0 head turing.state turing.transitions
	(newtape,newstate,newcommand)	= ApplyTransition transition tape
	
	SelectTransition :: !Int !Head !State ![Transition] -> (!TrNr,!Transition)
	SelectTransition n head state [transition=:{start,sigma}:transitions]
		| head==sigma && state==start	= (n,transition)
		| otherwise						= SelectTransition (n+1) head state transitions
	SelectTransition _ _ _ _
		= (0,{start="",sigma='_',end="error",move='_'})
	
	ApplyTransition :: !Transition !Tape -> (!Tape,!State,!Comm)
	ApplyTransition {end,move} tape
		| end=="error"	= (tape,end,ErrorT)
		| move=='L'		= left tape end
						with
							left :: !Tape !State -> (!Tape,!State,!Comm)
							left tape end
								| tape.head==0			= (tape,"error",ErrorL)
								| otherwise				= ({tape & head=tape.head-1},end,MoveL)
		| move=='R'		= right tape end
						with
							right :: !Tape !State -> (!Tape,!State,!Comm)
							right tape=:{content,head} end
								| pos>=size content		= ({content=content+++"#",head=pos},end,MoveR1)
								| otherwise				= ({tape & head=pos},end,MoveR)
							where
								pos						= head+1
		| otherwise		= write tape move end
						with
							write :: !Tape !Char State -> (!Tape,!State,!Comm)
							write tape=:{content,head} move end
								| move=='#'				= ({tape & content=content:=(head,'#')},end,Erase)
								| move==content.[head]	= (tape,end,None)
								| otherwise				= ({tape & content=content:=(head,move)},end,Write move)


//	Functions to inspect and change the tape.
CellContents :: !Int !Tape -> Char
CellContents pos {content,head}
	| pos>=NrOfCells content	= '#'
	| otherwise					= content.[head]

ChangeCellContents :: !Int !Char !Tape -> Tape
ChangeCellContents pos cell tape=:{content,head}
	| pos>=NrOfCells content	= {tape & content=content+++toString cell}
	| otherwise					= {tape & content=content:=(head,cell)}

MoveHead :: !Int !Tape -> Tape
MoveHead pos tape=:{content,head}
	| pos>=length				= {tape & content=ExtendContents content head length}
	| otherwise					= tape
where
	length						= NrOfCells content
	
	ExtendContents :: !String !Int !Int -> String
	ExtendContents content max pos
		| pos>max				= content
		| otherwise				= ExtendContents (content+++"#") max (pos+1)

NrOfCells :: !String -> Int
NrOfCells cont = size cont


//	Functions to inspect and change the transitions.
GetTransition :: Int ![Transition] -> Transition
GetTransition n trs
	| isEmpty trs	= {start="",sigma=' ',end="",move=' '}
	| n==0			= hd trs
	| otherwise		= GetTransition (n-1) (tl trs)

ChangeTransition :: Int Transition ![Transition] -> [Transition]
ChangeTransition n t trs
	| isEmpty trs	= [t]
	| n==0			= [t:tl trs]
	| otherwise		= [hd trs:ChangeTransition (n-1) t (tl trs)]

RemoveTransition :: Int ![Transition] -> [Transition]
RemoveTransition n trs
	| isEmpty trs	= trs
	| n==0			= tl trs
	| otherwise		= [hd trs:RemoveTransition (n-1) (tl trs)]

NrOfTransitions :: ![Transition] -> Int
NrOfTransitions	trs
	= length trs
