I have the following code that compiles and runs fine. I tried to make it more compact by replacing case newEmployee of with case scanEmployee p of, but it didn't work. There's probably an easy way to remove newEmployee (and newTeam) from the code right?
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) (Either String [Employee'])
scanTeam [ ] = return (Right [])
scanTeam (p:ps) = do
newEmployee <- scanEmployee p
case newEmployee of
Left errorMsg -> return (Left errorMsg)
Right e -> do
newTeam <- scanTeam ps
case newTeam of
Right n -> return (Right (e:n))
Left errorMsg -> return (Left errorMsg)
scanEmployee :: Employee -> State (Int,Int) (Either String Employee')
-- actual code for scanEmployee omitted ...
2 Answers 2
You could use LambdaCase and be explicit with >>= instead of using do blocks. The result is not much shorter:
scanEmployee p >>= \case
Left errorMsg -> return (Left errorMsg)
Right e -> do ...
1 Comment
You can simplify your code a bit with mapM and sequence:
mapM scanEmployee :: [Employee] -> State (Int, Int) [Either String Employee')
sequence :: [ Either String a ] -> Either String [ a ]
(Note that these type signatures are simplifications and the actual types are more general. Specifically mapM and sequence work for any monad (not just Either String) and any traversable (not just ([])))
And write a simple solution:
scanTeam = fmap sequence . mapM scanEmployee
ExceptT. It'd cut down the staircase ofcases significantly.