[Haskell-cafe] monad question

Andrew Harris andrew.unit at gmail.com
Sun Sep 19 13:40:59 EDT 2004

Hi everyone,

  Well, I'm trying to build a soccer server client and am using
Haskell.  I thought I was muddling through well enough... but I have
some questions.  I am using the Robot monad that I copied from Hudak's
book HSOE from page 272 (assuming I would understand it later).

Here's the monad code I copied:

newtype Robot a = Robot (RobotState -> IO (RobotState, a))

instance Monad Robot where
        return a = Robot (\s -> return (s, a))
        Robot sf0 >>= f =
              Robot (\s0 -> do
                               (s1, a1) <- sf0 s0
                               let Robot sf1 = f a1
                               (s2, a2) <- sf1 s1
                               return (s2, a2))

updateState :: (RobotState -> RobotState) -> Robot ()
updateState u = Robot (\s -> return (u s, ()))

queryState :: (RobotState -> a) -> Robot a
queryState q = Robot (\s -> return (s, q s))

I defined myself a comfortable "chunk of state" (comfortable for today
at least):

data RobotState =
    RobotState { player_type :: RobotType,
                 team_name :: String,
                 my_current_position :: Position,
                 visible_flags :: [ObjInfo],
                 visible_ball :: [ObjInfo],
                 visible_friends :: [ObjInfo],
                 visible_foes :: [ObjInfo],
                 audible_player_messages :: [String],
                 my_current_mode :: RobotMode,
                 debug_level :: [RobotDebugLevel],
                 my_uniform_number :: Integer,
                 game_mode :: GameMode,
                 game_clock :: Integer } deriving Show

In addition, I added some support functions similar to the ones he
wrote in Section 19.3.1:

assign_flags :: [ObjInfo] -> Robot ()
assign_flags flaglist = updateState (\s -> s {visible_flags = flaglist})

assign_friends :: [ObjInfo] -> Robot ()
assign_friends friendlist = updateState (\s -> s {visible_friends = friendlist})

assign_foes :: [ObjInfo] -> Robot ()
assign_foes foelist = updateState (\s -> s {visible_foes = foelist})

assign_ball :: [ObjInfo] -> Robot ()
assign_ball balllist = updateState (\s -> s {visible_ball= balllist})

Now, I read several online monad tutorials and kind of understand the
notion of a thread of function calls.  And I know that the do notation
is syntactic sugar for the bind operation.  But the code I've written
is really nasty.  For example, here is part of my code that handles a
see record and returns a new RobotState:

handleSeeRecord :: [SeeObjInfo_type] -> RobotState -> IO (RobotState, ())
handleSeeRecord seeobjlist p = do flaglist <- return (morphToList
flagFinder seeobjlist)
                                 balllist <- return (morphToList
ballFinder seeobjlist)
                                 friendlist <- return (morphToList
friendFinder seeobjlist)
                                 foelist <- return (morphToList
foeFinder seeobjlist)
                                 Robot e <- return (assign_flags
(flagSpread flaglist))
                                 Robot f <- return (assign_ball balllist)
                                 Robot g <- return (assign_friends friendlist)
                                 Robot h <- return (assign_foes foelist)
                                 (r', ()) <- e p
                                 (r'', ()) <- f r'
                                 (r''', ()) <- g r''
                                 h r'''

This actually works, but I think it can be improved with the bind
operation >>= somehow.  I tried a few alternatives but couldn't find
one that worked.  I ended up with this because it seems I had to
"strip" the type off of "return (assign_flags (flagSpread flaglist))"
and get the "e" that was a function.  Might someone have a suggestion
on how to improve this?


More information about the Haskell-Cafe mailing list