Je suis en train de travailler sur un Haskell projet qui consiste à attacher un grand noeud: je suis de l'analyse d'une représentation sérialisée d'un graphe où chaque nœud est à un certain décalage dans le fichier, et peut faire référence à un autre nœud par son décalage. J'ai donc besoin de construire une carte à partir de compensation des nœuds lors de l'analyse, qui, je peux nourrir à moi-même dans un do rec
bloc.
J'ai ce travail, et un peu-sorta-raisonnablement abstrait dans un StateT
-esque monade transformateur:
{-# LANGUAGE DoRec, GeneralizedNewtypeDeriving #-}
import qualified Control.Monad.State as S
data Knot s = Knot { past :: s, future :: s }
newtype RecStateT s m a = RecStateT (S.StateT (Knot s) m a) deriving
( Alternative
, Applicative
, Functor
, Monad
, MonadCont
, MonadError e
, MonadFix
, MonadIO
, MonadPlus
, MonadReader r
, MonadTrans
, MonadWriter w )
runRecStateT :: RecStateT s m a -> Knot s -> m (a, Knot s)
runRecStateT (RecStateT st) = S.runStateT st
tie :: MonadFix m => RecStateT s m a -> s -> m (a, s)
tie m s = do
rec (a, Knot s' _) <- runRecStateT m (Knot s s')
return (a, s')
get :: Monad m => RecStateT s m (Knot s)
get = RecStateT S.get
put :: Monad m => s -> RecStateT s m ()
put s = RecStateT $ S.modify $ \ ~(Knot _ s') -> Knot s s'
L' tie
fonction est où la magie se produit: l'appel à l' runRecStateT
produit une valeur et un état, qui je le nourrir que de son propre avenir. Notez que get
vous permet de lire à la fois le passé et l'avenir des états, mais put
seulement permet de modifier le "présent".
Question 1: est-ce à sembler comme une manière décente pour mettre en œuvre ce nouage modèle en général? Ou mieux encore, quelqu'un a mis en œuvre une solution générale à ce que j'ai négligé lors de l'espionnage à travers Hackage? J'ai battu ma tête contre l' Cont
monade pour un certain temps, car il semblait peut-être plus élégant (voir poste similaire de Dan Burton), mais je ne pouvais tout simplement pas travailler.
Totalement subjective de la Question 2: je ne suis pas totalement heureux avec la façon dont mon code d'appel se termine à la recherche:
do
Knot past future <- get
let {- ... -} = past
{- ... -} = future
node = {- ... -}
put $ {- ... -}
return node
Détails de mise en œuvre ici omis, évidemment, le point important étant que je dois obtenir l' past
et future
état, modèle correspondre à l'intérieur d'une liaison let (ou explicitement, l'ancien patron de paresseux) pour en extraire ce que je me soucie, puis construire mon nœud, mise à jour de mon état, et enfin retourner le nœud. Semble inutilement verbeux, et j'ai surtout l'aversion combien il est facile de faire accidentellement le motif que des extraits de l' past
et future
états stricte. Donc, quelqu'un peut-il penser à une interface plus conviviale?