@@ -83,7 +83,6 @@ consisting of numbers 1,2,3,4,5,6,7 with 4 being the active number.
8383(move 'right t) => '(tape (4 3 2 1) 5 (6 7))
8484```
8585
86- <!--
8786::: details Solution
8887``` racket
8988(define (change op t)
@@ -101,7 +100,6 @@ consisting of numbers 1,2,3,4,5,6,7 with 4 being the active number.
101100 (tape (cons val left) (car right) (cdr right))]))
102101```
103102:::
104- -->
105103
106104## Task 2
107105Modify the implementation of the interpreter from the lecture so that it uses your purely functional tape.
@@ -204,6 +202,85 @@ For your convenience, my complete implementation is shown below.
204202```
205203:::
206204
205+ ::: details Final solution
206+ ``` racket
207+ #lang racket
208+
209+ ;;; Task 1 - make purely functional tape
210+ (struct tape (left val right) #:transparent)
211+
212+ (define (fresh-tape size)
213+ (tape '() 0 (make-list (- size 1) 0)))
214+
215+ (define (change op t)
216+ (tape (tape-left t)
217+ (op (tape-val t) 1)
218+ (tape-right t)))
219+
220+ (define (move dir t)
221+ (match (cons dir t)
222+ [(cons 'left (tape '() _ _)) (error "Outside tape")]
223+ [(cons 'right (tape _ _ '())) (error "Outside tape")]
224+ [(cons 'left (tape left val right)) (tape (cdr left) (car left) (cons val right))]
225+ [(cons 'right (tape left val right)) (tape (cons val left) (car right) (cdr right))]))
226+
227+ ;;; Task 2 - modify the interpreter of Brainf*ck from the lecture to be purely functional
228+ ; Sample program adding two numbers
229+ (define add-prg
230+ '(@ > @ [- < + >] < *)
231+ )
232+
233+ ; Sample program multiplying two numbers
234+ (define mul-prg
235+ '(@ > @ < [- > [- > + > + < <] > [- < + >] < <] > > > *)
236+ )
237+
238+ ; constant for the size of the tape
239+ (define SIZE 10)
240+
241+ (define (eval-comma prg input t)
242+ (define new-tape
243+ (match (cons input t)
244+ [(cons '() _) (error "Empty input")]
245+ [(cons (list val z ...) (tape left _ right)) (tape left val right)]))
246+ (eval-prg prg (cdr input) new-tape))
247+
248+ (define (eval-cmd cmd prg input t)
249+ (let ([new-t
250+ (match cmd
251+ ['+ (change + t)]
252+ ['- (change - t)]
253+ ['< (move 'left t)]
254+ ['> (move 'right t)]
255+ ['* (printf "~a " (tape-val t)) t]
256+ [_ (error "Unknown command")])])
257+ (eval-prg prg input new-t)))
258+
259+ (define (eval-cycle cycle prg input t)
260+ (if (= (tape-val t) 0)
261+ (eval-prg prg input t)
262+ (begin
263+ (let* ([cycle-result (eval-prg cycle input t)]
264+ [new-input (car cycle-result)]
265+ [new-t (cadr cycle-result)])
266+ (eval-cycle cycle prg new-input new-t)))))
267+
268+ (define (eval-prg prg input t)
269+ (displayln t)
270+ (match prg
271+ [(list) (list input t)]
272+ [(list '@ rest ...) (eval-comma rest input t)]
273+ [(list (? list? cmd) rest ...) (eval-cycle cmd rest input t)]
274+ [(list cmd rest ...) (eval-cmd cmd rest input t)]))
275+
276+ (define (run-prg prg input)
277+ (eval-prg prg input (fresh-tape SIZE))
278+ (printf "done~n"))
279+
280+ (run-prg add-prg '(12 5))
281+ ```
282+ :::
283+
207284<!--
208285/*
209286A solution to Task 2 can be found [[https://drive.google.com/file/d/1tPR3ZxEop3l7qmHoywekLTuc7KhwgS_x/view?usp=sharing|here]].
0 commit comments