Based on the List monad I set out to define Monad instances for the Map type from Data.Map, to perform chained unions and folds on Maps like lists, but with the efficient sorting and merging of Maps:
{-# LANGUAGE FlexibleInstances #-}
import qualified Data.Map as M
instance Monad (M.Map Integer) where
return = M.singleton 0
f >>= g = M.foldr (\a -> M.union (g a)) M.empty f
This compiles fine but I would like g to be sensitive to the key of each value that it operates on. That would allow the output of g to have staggered keys for richer unioning behaviour. This is fictional Haskell and doesn't typecheck but it would be nice to have:
type PairMap (a,b) = Map a b
instance Monad PairMap where
return :: (k,a) -> PairMap (k,a)
return (k,a) = M.singleton k a
(>>=) :: PairMap (k,a) -> ((k,a) -> PairMap (k',a')) -> PairMap (k',a'))
f >>= g = M.foldrWithKey (\(k,a) -> M.union (g k a)) M.empty f
If you replace PairMap (a,b) with [(a,b)] you get exactly the List monad back again. But GHC doesn't allow me to cheat and turn the two parameters of Map into one pair. The best I could manage was something like this: (I had to add the Ord c constraint to typecheck with unions)
class PairMonad m where
return2 :: a -> b -> m a b
(>>==) :: (Ord c) => m a b -> (a -> b -> m c d) -> m c d
instance PairMonad M.Map where
return2 = M.singleton
f >>== g = M.foldrWithKey (\k a -> M.union (g k a)) M.empty f
I hope you can see how similar this is to the PairMap dream, so it should be possible to do this more elegantly with established monadic magic or other concepts related to monads. I don't need it to be a monad as long as I can achieve that "key-sensitive bind."
Last Resort
- If there's no way to do this elegantly then I'll resort to collapsing
each
Mapto a key-value list[(a,b)]and use the List monad. - One might suggest including the key into the value to help
gcompute on the key, but I see that as contaminating the value with extraneous information.
g k awould differ fromg a? Technically I believe that ifgcould look at the keys it would violate the monad laws. However, there may be another data structure or formulation which can accomplish what you want to do.kwere integers anda's were lists then I might wantg k [True,False,True] == M.fromList [((k,1),True),((k,2),False),((k,3),True)]such that theMapresulting from the bind has pairs of integers as keys which are sorted in lexicographic order, remembering the priorMapstructure. I wouldn't be able to achieve this ing awhich can't compute on the key ofa. I just want to know if there's an existing solution to this, it doesn't have to be a monad.