ISL+ 中的有限状态机仿真实现(球拍)



我是一个新手,独自研究HTDP2(Felleisen等人),但一直停留在第四章的问题#380 - 交织数据。问题出在创建DSL的上下文中,但我首先重新熟悉了一个通用的FSM模拟器,并提供了以下代码:

; An FSM is a [List-of 1Transition]
; A 1Transition is a list of two items:
;   (cons FSM-State (cons FSM-State '()))
; An FSM-State is a String that specifies a color
; data examples 
(define fsm-traffic
'(("red" "green") ("green" "yellow") ("yellow" "red")))
; FSM FSM-State -> FSM-State 
; matches the keys pressed by a player with the given FSM 
(define (simulate state0 transitions)
(big-bang state0 ; FSM-State
[to-draw
(lambda (current)
(overlay (text current 12 "black")
(square 100 "solid" current)))]
[on-key
(lambda (current key-event)
(find transitions current))]))
; [X Y] [List-of [List X Y]] X -> Y
; finds the matching Y for the given X in alist
(define (find alist x)
(local ((define fm (assoc x alist)))
(if (cons? fm) (second fm) (error "not found"))))

然后问题说明如下:

重新制定 1Transition 的数据定义,以便可以将过渡限制为某些击键。尝试制定更改,以便find继续工作而无需更改。您还需要更改什么才能使整个程序正常工作?设计配方的哪一部分提供了答案?有关原始练习陈述,请参阅练习 229。

练习 229 引入了一个结构类型定义来跟踪状态和转换,但由于问题陈述要求我保持在提供的find函数内,我很难提出类似的结构类型的定义。相反,我想出了以下数据定义:

; An FSM is a [List-of Transition]
; A Transition is a two-item list of the following form:
; (cons FSM-State (cons (cons KeyEvent (cons FSM-State '()))'()))
; data example
(define fsm-traffic (list (list "red" (list "r" "green"))
(list "green" (list "g" "yellow"))
(list "yellow" (list "y" "red"))))

因此,我得到(find fsm-traffic "green")(list "g" "yellow")因此修改了on-key子句如下:

(lambda (current key-event)
(if (string=? key-event (first (first (rest (first transitions)))))
(second (find transitions current))
(error "invalid input")))

现在,如果我以 State0 呈现(simulate "red" fsm-traffic)启动程序,如果我按"r",它会转到"绿色"FSM 状态,但随后它不会接受"g"进入以下状态,依此类推。

如果我以(simulate "yellow" fsm-traffic)开始世界程序,那么FSM状态"黄色"被渲染,但它不会过渡到任何其他状态(error子句被激活);类似地,"绿色"作为起始状态。

我的预感是,由于我首先用"红色"状态定义了fsm-traffic,因此它接受其输入以过渡到"绿色",但由于其他状态不会发生同样的情况,因此big-bang不会"处理"transitions参数正确。但我只是不知道如何解决这个问题。我也不知道自从我的数据定义开始以来我是否出错了。

提前谢谢你帮助我。

P.D. 请让我知道我是否遵守了在堆栈溢出上发布的规则(这是我:)的第一篇文章。

您正确地确定了问题的根源。您首先定义了具有"red"状态和"r"转换的fsm-trafficon-key处理程序仅查看first。它在if问题中这样做:

(string=? key-event (first (first (rest (first transitions)))))
;                    ^                   ^
;                    |                   this makes it only look at `"red"`
;                    this makes it only look at `"r"` within that

这个if问题似乎很复杂。就像我们做的那样,如果它是一个具有签名和目的的函数,我们可以设计这个表达式的输入、输出和用途。

输入:它应该依赖什么?

哪些键有效取决于转换表,但也取决于当前状态。这就是为什么只有"r""red"州有效,而"g""green"州有效的原因。所以它的输入是:

current : FSM-State
key-event : KeyEvent
transitions : FSM

现有表达式忽略current

产出和目的

这是一个if问题,因此它应该输出一个Boolean。此布尔值的目的是确定密钥在当前状态下是否有效。

当表中current状态和key-event状态都存在任何转换时,它应该是 true。

这个带有">任何"和">两者"的目的陈述听起来很复杂,它应该成为它自己的功能。使用我们刚刚做出的输入、输出和目的:

;; FSM-State KeyEvent FSM -> Boolean
;; Determines whether there is any transition in the FSM table for both the current
;; state and the key event.
(define (transition-for-state-and-key? state key table)
....)

您当前对身体的表达不包括state

(string=? key (first (first (rest (first table)))))

但实际的身体应该取决于statekey

就像这两者都取决于两者一样,find函数也应该取决于statekey

;; FSM-State KeyEvent FSM -> FSM-State
;; Finds the matching transition-state from the given state with the given key in the table.
(define (find-transition-state state key table)
....)

并注意transition-for-state-and-key?find-transition-state之间的关系。当transition-for-state-and-key?函数不会出错时,find-transition-state函数应该准确地返回 true。

这应该足以让您继续。

最新更新