【发布时间】:2019-07-27 05:29:32
【问题描述】:
我正在尝试创建一个状态单子来存储游戏的当前状态,该状态接受语句(命令)列表以返回操作列表。
turbo 命令单独工作,但顺序执行,之前的命令对当前命令没有任何影响。
我不太明白的是,这些状态应该如何传播到下一个命令?如果我手动运行代码,我会执行以下操作:
s0 = turbo (PenDown)
s1 = turbo (Forward (RLit 50))
s2 = turbo (Turn (RLit 90))
s3 = turbo (Forward (RLit 50))
s4 = turbo (Turn (RLit 90))
s5 = turbo (Forward (RLit 50))
a1 = snd (deState s1 (fst (deState s1 (fst (deState s0 initTurboMem)))))
a2 = snd (deState s3 (fst (deState s2 (fst (deState s1 (fst (deState s1 (fst (deState s0 initTurboMem)))))))))
a3 = snd (deState s5 (fst (deState s4 (fst (deState s3 (fst (deState s2 (fst (deState s1 (fst (deState s1 (fst (deState s0 initTurboMem)))))))))))))
a = a1 ++ a2 ++ a3
这将给出答案,但我不确定在下面的代码中如何完成。
要运行代码,请使用以下代码
stmt = Seq [
PenDown
, Forward (RLit 50)
, Turn (RLit 90)
, Forward (RLit 50)
, Turn (RLit 90)
, Forward (RLit 50)
]
snd (deState (turbo stmt) initTurboMem)
这里是有问题的函数,没有考虑以前的陈述
turbo (Seq [x]) = turbo x
turbo (Seq (x:xs)) = do
state <- get
let a0 = snd (deState (turbo x) state)
state <- get
let a1 = snd (deState (turbo (Seq xs)) state)
pure (a0 ++ a1)
这里是其余的功能
turbo :: Stmt -> State TurboMem [SVGPathCmd]
turbo (var := expr) = do
state <- get
let val = snd (deState (evalReal expr) state)
setVar var val
pure []
turbo PenDown = do
setPen True
pure []
turbo PenUp = do
setPen False
pure []
turbo (Turn expr) = do
state <- get
let angle = snd (deState (evalReal expr) state)
turn angle
pure []
turbo (Forward expr) = do
state <- get
let angle = snd (deState (getAngle) state)
dist = snd (deState (evalReal expr) state)
x = dist * cos (angle * pi / 180)
y = dist * sin (angle * pi / 180)
pen = snd (deState (getPen) state)
if pen then pure [LineTo x y] else pure [MoveTo x y]
涡轮状态
data TurboMem = TurboMem (Map String Double) Double Bool
deriving (Eq, Show)
表达式和语句
data RealExpr
= RLit Double -- literal/constant
| RVar String -- read var's current value
-- if uninitialized, the answer is 0
| Neg RealExpr -- unary minus
| RealExpr :+ RealExpr -- plus
| RealExpr :- RealExpr -- minus
| RealExpr :* RealExpr -- times
| RealExpr :/ RealExpr -- divide
deriving (Eq, Ord, Read, Show)
data Stmt
= String := RealExpr -- assignment, the string is var name
| PenDown -- set pen to down (touch paper) state
| PenUp -- set pen to up (away from paper) state
| Turn RealExpr -- turn counterclockwise by given degrees
-- negative angle just means clockwise
| Forward RealExpr -- move by given distance units (in current direction)
-- negative distance just means backward
-- if pen is down, this causes drawing too
-- if pen is up, this moves without drawing
| Seq [Stmt] -- sequential compound statement. run in given order
deriving (Eq, Ord, Read, Show)
data SVGPathCmd = MoveTo Double Double -- move without drawing
| LineTo Double Double -- draw and move
deriving (Eq, Ord, Read, Show)
操作状态的辅助函数
-- Get current direction.
getAngle :: State TurboMem Double
-- Change direction by adding the given angle.
turn :: Double -> State TurboMem ()
-- Get pen state.
getPen :: State TurboMem Bool
-- Set pen state.
setPen :: Bool -> State TurboMem ()
-- Get a variable's current value.
getVar :: String -> State TurboMem Double
-- Set a variable to value.
setVar :: String -> Double -> State TurboMem ()
初始状态
initTurboMem = TurboMem Map.empty 0 False
我希望结果是
[LineTo 50.0 0.0,LineTo 0.0 50.0,LineTo -50.0 0.0]
但我真正得到的是
[MoveTo 50.0 0.0,MoveTo 50.0 0.0,MoveTo 50.0 0.0]
【问题讨论】:
-
快速提问:简而言之,
turbo应该做什么?了解预期目的可能有助于诊断问题。 -
@bradrn
turbo应该接受Stmt并返回State,结果TurboMem(存储地图和变量的状态)和SVGPathCmd的列表(这只是由声明确定的MoveTo x y和LineTo x y)。