[racket] htdp/2e: exercise 197, a solution, feedback welcome

From: Daniel Bastos (dbastos at toledo.com)
Date: Wed Jan 21 08:03:02 EST 2015

I had a lot of difficulties with exercise 195, 196, 197. I'm posting my
solution to exercise 197 to get a chance to get feedback. How would have
you represented the FSM from exercise 100?

;Exercise 197. Consider the following data representation for finite state
machines:
(define-struct fsm (initial transitions final))
(define-struct transition (current key next))

; An FSM.v2 is a structure:
;   (make-fsm FSM-State LOT FSM-State)
; A LOT is one of:
; – empty
; – (cons Transition.v3 LOT)
; A Transition.v3 is a structure:
;   (make-transition FSM-State KeyEvent FSM-State)

;Represent the FSM from exercise 100 in this context.
;Design the function fsm-simulate, which accepts an FSM.v2 and runs it on a
player’s key strokes. If the sequence of key strokes force the FSM.v2 to
reach a final state, fsm-simulate stops. Hint The function uses the initial
field of the given fsm structure to keep track of the current state.

;(*) Solution

(define-struct fsm (initial transitions final))
(define-struct transition (current key next))

; An FSM.v2 is a structure:
;   (make-fsm FSM-State LOT FSM-State)
; A LOT is one of:
; – empty
; – (cons Transition.v3 LOT)
; A Transition.v3 is a structure:
;   (make-transition FSM-State KeyEvent FSM-State)

; a(b|c)*d

(define AA "start, expect to see an 'a' next")
(define BC "expect to see: 'b', 'c', or 'd'")
(define DD "encountered a 'd', finished")
(define ER "error, user pressed illegal key")

(define fsm-exe100
  (make-fsm AA
            (list (make-transition AA "a" BC)
                  (make-transition BC "b" BC)
                  (make-transition BC "c" BC)
                  (make-transition BC "d" DD)
                  (make-transition AA "d" DD))
            DD))

; code begins

(define CANVAS (empty-scene 300 20))

(define (show-state a-fsm)
  (place-image (text (fsm-initial a-fsm) 14 "black")
               100 10 CANVAS))

; FSM -> SimulationState.v2
; match the keys pressed by a player with the given FSM
(define (fsm-simulate a-fsm)
   (big-bang a-fsm
             (to-draw show-state)
             (on-key find-next-state)
             (stop-when last-state?)))

; SimulationState.v2 -> Boolean
(define (last-state? world-fsm)
  (string=? (fsm-initial world-fsm) (fsm-final world-fsm)))

(check-expect (not (last-state? fsm-exe100)) true)

; Transition.v3 Transition.v3 -> Boolean
(define (transition=? t1 t2)
  (and
   (string=? (transition-current t1) (transition-current t2))
   (string=? (transition-key t1) (transition-key t2))
   (string=? (transition-next t1) (transition-next t2))))

; FSM.v2 KeyEvent -> FSM.v2
; produces the machine with the next state associated with ke
(define (find-next-state a-fsm ke)
  (make-fsm (find (fsm-transitions a-fsm) (fsm-initial a-fsm) ke)
            (fsm-transitions a-fsm)
            (fsm-final a-fsm)))

; [List-of transition] FSM-State KeyEvent -> FSM-State
; finds the next FSM-State in the transition where 'current' is located
(define (find ls current ke)
  (cond
    [(empty? ls) (error (string-append "not found: " ke " " current))]
    [else (cond
            [(and (string=? current (transition-current (first ls)))
                  (key=? ke (transition-key (first ls))))
             (transition-next (first ls))]
            [else
             (find (rest ls) current ke)])]))

(check-error (find (fsm-transitions fsm-exe100) AA "b"))
(check-expect (find (fsm-transitions fsm-exe100) AA "a") BC)
(check-expect (find (fsm-transitions fsm-exe100) BC "b") BC)
(check-expect (find (fsm-transitions fsm-exe100) BC "c") BC)
(check-expect (find (fsm-transitions fsm-exe100) BC "d") DD)

(check-error (find-next-state fsm-exe100 "b"))
(check-expect (find-next-state fsm-exe100 "a") (make-fsm BC
(fsm-transitions fsm-exe100) DD))

(check-expect (find-next-state
               (find-next-state fsm-exe100 "a") "b")
              (make-fsm BC (fsm-transitions fsm-exe100) DD))

(check-expect (find-next-state
               (find-next-state
                (find-next-state fsm-exe100 "a") "b") "c")
              (make-fsm BC (fsm-transitions fsm-exe100) DD))

(check-expect (find-next-state
               (find-next-state
                (find-next-state
                 (find-next-state fsm-exe100 "a") "b") "c") "d")
              (make-fsm DD (fsm-transitions fsm-exe100) DD))

(check-expect (find-next-state
                 (find-next-state fsm-exe100 "a") "d")
              (make-fsm DD (fsm-transitions fsm-exe100) DD))
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20150121/39a0b8ef/attachment.html>

Posted on the users mailing list.