
Duncan Coutts wrote:
On Thu, 2008-09-18 at 15:43 -0300, Andre Nathan wrote:
My Graph type is the following.
data Graph a b = Graph { adjacencies :: Map Int (a, (Map Int b)) , numVertices :: Int , numEdges :: Int }
addVertex :: Int -> a -> State (Graph a b) () addVertex vertex label = do g <- get let adj = Map.insert vertex (label, Map.empty) (adjacencies g) put $ g { adjacencies = adj, numVertices = numVertices g + 1 }
So I'm confused right now about how I should proceed. Any hints regarding that?
To be honest I would not bother with the state monad and just make them pure operations returning new graphs:
addVertex :: Int -> a -> Graph a b -> Graph a b
It's very common to have this style, ie returning a new/updated structure explicitly rather than implicitly in a state monad. Just look at the Data.Map api for example. If you later want to stick it in a state monad then that would be straightforward but also easy to use directly.
I agree. Duncan's version also looks more atomic to me, because Andre's version (that's renamed to addVertexM below) could be easily derived by: addVertexM v l = modify (addVertex v l) The opposite derivation is also possible but does additional wrapping into and out of a state: addVertex v l = execState (addVertexM v l) (Furthermore the module Control.Monad.State is "non-portable", because get, put, modify and gets come in via the MonadState class, but separate not overloaded versions for these function would make sense in the same way we have "map" despite "fmap".) Cheers Christian