#lang racket
(require (planet "main.rkt" ("samsergey" "rewrite.plt" 1 0))
rackunit)
(struct Tape (the-left-part the-current-record the-right-part))
(define/. initial-tape
(cons h t) --> (Tape '() h t))
(define (snoc a b) (cons b a))
(define/. shift-right
(Tape '() '() (cons h t)) --> (Tape '() h t) (Tape l x '()) --> (Tape (snoc l x) '() '()) (Tape l x (cons h t)) --> (Tape (snoc l x) h t))
(define/. flip-tape
(Tape l x r) --> (Tape r x l))
(define shift-left
(compose flip-tape shift-right flip-tape))
(define/. get
(Tape _ v _) --> v)
(define/. put
'() t --> t
v (Tape l _ r) --> (Tape l v r))
(define (revappend a b)
(foldl cons b a))
(define/. show-tape
(Tape '() '() '()) --> '()
(Tape l '() r) --> (revappend l (cons '() r))
(Tape l v r) --> (revappend l (cons (list v) r)))
(define/. interprete
(list S v 'r) tape --> (list S (shift-right (put v tape)))
(list S v 'l) tape --> (list S (shift-left (put v tape)))
(list S v 'p) tape --> (list S (put v tape))
(list S _) tape --> (list S tape))
(define (run-turing prog t0 verbose)
((replace-repeated
`(,S ,T) --> (begin
(when verbose (printf "~a\t~a\n" S (show-tape T)))
(interprete (prog `(,S ,(get T))) T)))
(list 'Start (initial-tape t0))))
(define-syntax-rule (Turing-Machine prog ...)
(λ (l #:verbose? (verbose #t))
(when verbose (displayln "STATE\tTAPE"))
((/. (list _ t) --> (flatten (show-tape t)))
(run-turing (replace prog ...) l verbose))))
(define ADD1
(Turing-Machine
'(Start 1) --> '(Start 1 r)
'(Start 0) --> '(Start 0 r)
'(Start ()) --> '(Add () l)
'(Add 0) --> '(End 1 p)
'(Add 1) --> '(Add 0 l)
'(Add ()) --> '(End 1 p)))
(ADD1 '(1 0 1 1 1 1))
(ADD1 (ADD1 '(1 1 0)))
(check-equal? (ADD1 '(1 0 1) #:verbose? #f) '(1 1 0))
(check-equal? (ADD1 '(0) #:verbose? #f) '(1))
(check-equal? (ADD1 '(1) #:verbose? #f) '(1 0))
(check-equal? (ADD1 '(1 1 1) #:verbose? #f) '(1 0 0 0))
(define ADDER
(Turing-Machine
'(Start 1) --> '(Drag * r)
'(Start +) --> '(Start + r)
'(Start =) --> '(End = p)
'(Drag ()) --> '(Return 1 l)
`(Drag ,x) --> `(Drag ,x r)
'(Return *) --> '(Start 1 r)
`(Return ,x) --> `(Return ,x l)))
(check-equal? (ADDER '(1 + 1 =) #:verbose? #f) '(1 + 1 = 1 1))
(check-equal? (ADDER '(1 1 + 1 1 1 =) #:verbose? #f) '(1 1 + 1 1 1 = 1 1 1 1 1))
(check-equal? (ADDER '(1 1 + 1 + 1 1 =) #:verbose? #f) '(1 1 + 1 + 1 1 = 1 1 1 1 1))
(check-equal? (ADDER '(1 1 =) #:verbose? #f) '(1 1 = 1 1))