3
\$\begingroup\$

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?

nponeccop
1,1045 silver badges10 bronze badges
asked Sep 14, 2012 at 8:53
\$\endgroup\$
1
  • \$\begingroup\$ Have you considered traverseWithKey? \$\endgroup\$ Commented Feb 28, 2014 at 4:51

1 Answer 1

5
\$\begingroup\$

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)
answered Sep 14, 2012 at 9:44
\$\endgroup\$
1
  • \$\begingroup\$ Ah, liftM2, that's how it is used! \$\endgroup\$ Commented Sep 14, 2012 at 16:40

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.