Reputation: 7162
Somewhat similar to this question, I'm trying to figure out
how to move around a Haskell Monad state.
Each Employee
in a team is replaced with a corresponding Employee'
while maintaining some simple state. Here is the code:
module Main( main ) where
import Control.Monad.State
data Employee = EmployeeSW Int Int | EmployeeHW Int String deriving ( Show )
data Employee' = EmployeeSW' Int | EmployeeHW' String deriving ( Show )
scanTeam :: [Employee] -> State (Int,Int) [Employee']
scanTeam [ ] = return []
scanTeam (p:ps) = scanEmployee p -- : scanTeam ps ???
scanEmployee :: Employee -> State (Int,Int) Employee'
scanEmployee (EmployeeSW id s) = do
(num,raise) <- get
put (num+1,raise)
return (EmployeeSW' (s+raise))
scanEmployee (EmployeeHW id s) = do
(num,raise) <- get
put (num+1,raise)
return (EmployeeHW' (s++(show raise)))
startState = (0,3000)
t = [(EmployeeHW 77 "Hundred"),(EmployeeSW 66 500),(EmployeeSW 32 200)]
main = print $ evalState (scanTeam t) startState
I want to eventually concatenate scanEmployee p
with scanTeam ps
,
so I tried to extract the pieces of scanEmployee p
and somehow glue
them together with scanTeam ps
. So far I failed miserably.
Actually, I'm not even sure the state can be moved around between them (?).
Upvotes: 1
Views: 76
Reputation: 44634
Since State
is a monad, you can use do
notation to define State
computations.
(State
's instance of Monad
plumbs the state through, so the ending state of one statement in the do
block becomes the starting state of the next.)
So, in a do
block, I'm going to:
Employee
in the list to get a new Employee
State
ful computation.scanTeam :: [Employee] -> State (Int,Int) [Employee']
scanTeam [ ] = return []
scanTeam (p:ps) = do
newP <- scanEmployee p
newPs <- scanTeam ps
return (newP:newPs)
It turns out that "map
in a monadic context" is pretty useful in general, so it's present in the standard prelude as mapM :: Monad m => (a -> m b) -> [a] -> m [b]
(aka traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)
, if you're ready to go down the rabbit hole).
scanTeam = mapM scanEmployee
Upvotes: 4