Sulla base della monade List ho deciso di definire Monad
istanze per il tipo Map
da Data.Map
, per eseguire unioni e pieghe concatenate su Map
s come elenchi, ma con l'efficiente ordinamento e fusione di Map
s:
{-# 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
Questo compila bene, ma vorrei che g
sia sensibile alla chiave di ogni valore su cui opera. Ciò consentirebbe all'output di g
di avere chiavi sfalsate per un comportamento di unione più ricco. Questo è fittizio Haskell e non tipograficamente, ma sarebbe bello avere:
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
Se sostituisci PairMap (a,b)
con [(a,b)]
ottieni di nuovo esattamente la monade Elenco. Ma GHC non mi permette di imbrogliare e trasformare i due parametri di Map
in una coppia. Il meglio che potevo gestire era qualcosa del genere: (dovevo aggiungere il vincolo Ord c
a typecheck con i sindacati)
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
Spero che tu possa vedere quanto questo sia simile al sogno di PairMap
, quindi dovrebbe essere possibile farlo in modo più elegante con la magia monadica stabilita o altri concetti relativi alle monadi. Non ho bisogno che sia una monade finché riesco a ottenere quella "legatura sensibile alla chiave".
Ultimo resort
- Se non c'è modo di farlo elegantemente, farò ricorso al collasso
ogni
Map
a un elenco di valori-chiave[(a,b)]
e usa la lista monad. - Si potrebbe suggerire di includere la chiave nel valore per aiutare
g
a calcolare sulla chiave, ma la vedo come contamina il valore con informazioni estranee.