Tell me more ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I'm writing a monadic parser instance that transforms Data.Map.Map's:

instance (Ord a, FromEDN a, FromEDN b) => FromEDN (M.Map a b) where
    parseEDNv (E.Map m) = mapMmap parseEDNv parseEDN m
    parseEDNv v = typeMismatch "Map" v

Data.Map doesn't provide it's own mapM version like Data.Vector does, so i had to write it from scratch:

mapMmap :: (Ord a2, Monad m) => (a1 -> m a2) -> (b1 -> m b2) -> M.Map a1 b1 -> m (M.Map a2 b2)
mapMmap kf vf m = do
    let pairsIn = M.assocs m
    pairsOut <- mapM fs pairsIn
    return $! M.fromList pairsOut
    where
        fs (k, v) = do
            newK <- kf k
            newV <- vf v
            return (newK, newV)

It works, but very verbose. How to trim into a more succinct INLINEable version without too much black^W monadic magic?

share|improve this question

1 Answer

up vote 3 down vote accepted

There is keys library which implements

mapWithKeyM_ :: (FoldableWithKey t, Monad m) => (Key t -> a -> m b) -> t a -> m ()

and related functions for Data.Map.

There is also Data.Traversable.mapM, but it only maps over values. Mapping over both keys and values is not a mapM operation because there is Ord constraint.

If you still consider implementing your function yourself, it can be written like this:

import qualified Data.Map as M
import Control.Monad

mapMmap :: (Ord a2, Monad m) => 
   (a1 -> m a2) -> (b1 -> m b2) -> M.Map a1 b1 -> m (M.Map a2 b2)
mapMmap kf vf = liftM M.fromList . mapM fs . M.assocs 
    where
    fs (k, v) = liftM2 (,) (kf k) (vf v)
share|improve this answer
Ah, liftM2, that's how it is used! – wiz Sep 14 '12 at 16:40

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.