I'm trying to create use a state monad to store the current state of a game that takes in a list of statement (commands) to return a list of actions.
Individually, the turbo commands work, but done sequentially, the previous commands do not have any affect on the current command.
Something I don't really understand is how are the states suppose to be propagated down to the next commands? The following is what I would do if I was running the code manually:
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
This would give the answer, but I'm not sure how it would be done in the code below.
To run the code, use the following
stmt = Seq [
PenDown
, Forward (RLit 50)
, Turn (RLit 90)
, Forward (RLit 50)
, Turn (RLit 90)
, Forward (RLit 50)
]
snd (deState (turbo stmt) initTurboMem)
Here is the function in question that isn't taking previous statements into consideration
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)
Here are the rest of the functions
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]
The turbo state
data TurboMem = TurboMem (Map String Double) Double Bool
deriving (Eq, Show)
The expressions and statements
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)
Helper functions to manipulate the state
-- 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 ()
The initial state
initTurboMem = TurboMem Map.empty 0 False
I expect the result to be
[LineTo 50.0 0.0,LineTo 0.0 50.0,LineTo -50.0 0.0]
but what I actually get is
[MoveTo 50.0 0.0,MoveTo 50.0 0.0,MoveTo 50.0 0.0]
turbosupposed to do? Understanding the intended purpose may help with diagnosing the problem. - bradrnturbois suppose to take in aStmtand returnStatewith the resultingTurboMem(stores the state of the Map and variables) and a list ofSVGPathCmd(which are justMoveTo x yandLineTo x ydetermined by the Statements). - loiuytre35