[Haskell-cafe] Is StateT what I need?

Daniel Fischer daniel.is.fischer at web.de
Tue Dec 18 20:45:09 EST 2007


Am Dienstag, 18. Dezember 2007 19:47 schrieb Andre Nathan:
> Hello
>
> On Mon, 2007-12-17 at 21:22 -0200, Andre Nathan wrote:
> > Thanks everyone for the great suggestions. The code is much cleaner now
> > (not to mention it works :)
>
> I'm trying to finish the process tree construction but I guess I'll need
> some help again.
>
> My idea is to have a function that would return a map representing the
> process tree
>
> > createTree :: IO PsTree
> > createTree = do
> >   entries <- getDirectoryContents "/proc"
> >   return $ foldr buildTree Map.empty entries

I believe instead of return $ foldr... you should use
	evalStateT $ foldM (flip buildTree) Map.empty entries

>
> The "return $ foldr ..." part is missing something, because buildTree
>
> would have be something like:
> > buildTree :: String -> PsTree -> StateT PsMap IO PsTree
> > buildTree entry tree = do
> >   case matchRegex (mkRegex "^[0-9]+$") entry of
> >     Nothing -> return tree -- skip this entry
> >     Just _  -> do

where does 'dir' below come from? should the pattern match not be
	Just dir -> do ?
> >       psMap <- get
> >       if Map.member dir psMap
> >         then return tree -- alread inserted
> >         else return $ insertInTree dir tree

perhaps just
		else insertInTree dir tree
if insertInTree :: dirtype -> PsTree -> StateT PsMap IO PsTree

>
> so the types don't match. insertInTree would be something like (in
>
> pseudo-code):
> > insertInTree pid tree = do
> >   procInfo <- insertProc pid -- this inserts pid in the state map
> >                              -- and returns a PsInfo, so its type is
> >                              -- Pid -> StateT PsMap IO PsInfo.
> >                              -- Can I use it here though?

sure you can use it here, the monad is m = (StateT PsMap IO),
you can chain m a, m b, m Int, m PsTree, m PsInfo freely, as long as it's only 
the same m.

> >   psMap <- get
> >   if pid == "1" -- init is the root of the tree
> >     then do modify (Map.insert "1" procInfo psMap)
> >             return $ Map.insert "1" procInfo tree
> >     else do
> >       let pPid = parentPid procInfo
> >       if Map.member pPid psMap
> >         then do psMap' <- new psMap with pid appended pPid's children

rather: 	then do modify (insert pid in pPid's children)
			return tree

you don't do anything with the new map here, so no need to bind the name 
psMap' to it.
I believe here you want something like
modify (Map.adjust (Map.insert pid procInfo) pPid)
but perhaps you also want to insert pid into the PsMap?

> >                 return tree
> >         else do tree' <- insert pPid in the process tree
> >                 modify (new psMap with pid appended pPid's children)

Insert pPid in the PsMap before that?
I think, you can treat both cases at once using Map.insertWith.

> >                 return tree'
>
> insertProc was in my first message, and it's like this:
> > insertProc :: Pid -> StateT PsMap IO PsInfo
> > insertProc pid = do
> >   process <- lift $ procInfo pid
> >   psMap <- get

delete above line, it's dead code, originally you did
	psMap <- get
	put (Map.insert pid process psMap)

modify does both.

> >   modify (Map.insert pid process)
> >   return (process)
>
> At this point I'm not sure if this design is good or even correct.

I'm not sure what the design is, what's the role of PsMap and the PsTree, 
respectively?

> I'm mixing (StateT PsMap IO PsInfo) with (StateT PsMap IO PsTree), which I'm
> not sure I can do.

No problem :)

> There is probably a much cleaner way to do this but I
> cannot see through the types right now :/
>
> Anyone has any hints on how to make that scheme work?
>

Take a piece of paper and write down your intended algorithm. In that process, 
think about how to represent your data.
From that, much of the code becomes automatic (well, if you know the libraries 
better than I do, otherwise it's still a lot of searching the docs and 
looking what functions/data types are on offer).
It looks like a promising start, though it definitely needs some polishing.

Cheers,
Daniel


More information about the Haskell-Cafe mailing list