2014-05-02 1 views
0

A pris ma première fissure chez Monad Transformers. J'ai écrit un algorithme génétique simple pour ce que ma classe appelle le problème de «localisation de l'installation». L'algorithme n'est pas si important. J'ai généralement suivi le format expliqué dans ce chapitre de Real World Haskell.Appel de la fonction monadique à l'intérieur de la pile du transformateur

Ma pile de transformateur ressemble à ceci

newtype FacilityApp a = MyA { 
    runA :: RandT StdGen (ReaderT Environment (StateT (Population, Int) IO)) a 
    } deriving (Monad, MonadIO, MonadReader Environment, MonadState (Population,Int),  MonadRandom) 

runFacility :: FacilityApp a -> Input -> StdGen -> IO a 
runFacility k input g = 
    let env = mkEnv input defParms 
     (pop, g') = runRand (genInitialPopulation env) g 
     state = (pop, numRounds defParms) 
     ra = runA k 
     rr = runReaderT rrand env 
     rs = evalStateT rr state 
     rrand = evalRandT ra g' 
    in rs 

Plus tard dans mon code, je définir ma principale action « étape » pour l'exécution d'un tour de l'accouplement et de survivre. Dans mon action, je n'ai aucun problème à générer un nombre aléatoire et à l'utiliser. Cependant, je voudrais déplacer le caractère aléatoire d'une fonction particulière hors de l'action d'étape et dans cette fonction. Malheureusement, je reçois des erreurs de type, et j'ai besoin d'une formation sur les deux pourquoi cela ne fonctionne pas, et comment faire fonctionner ce travail.

Vous avez probablement ne pas vraiment besoin de cela, mais ma fonction mate points seulement deux vecteurs ensemble:

mate :: CustomerService -> CustomerService -> Int -> CustomerService  
mate a b split = (fst $ V.splitAt split a) V.++ (snd $ V.splitAt split b) 

Alors, cela fonctionne:

offspring' :: CustomerService -> CustomerService -> Int -> (CustomerService, CustomerService) 
offspring' a b split = (mate a b split, mate b a split) 

step :: FacilityApp [CustomerService] 
step = do 
    (pop, n) <- get 
    env <- ask 
    let e = (warehouses env, customers env) 
    let [email protected](p1:p2:_) = sortBy (sortByCost e) $ filter (validSolution e) pop 
    let (_:_:rest) = reverse sorted 
-- these next two lines are of my concern 
    split <- getRandomR (1, V.length p1) 
    let (c1,c2) = offspring' p1 p2 split 
-- eventually put the new children in the state and step again 
    put (c1:c2:rest, (n-1)) 
    if n > 0 then step else return pop 

mais je vraiment définir plutôt la progéniture comme donc:

offspring :: (RandomGen g) => CustomerService -> CustomerService -> Rand g (CustomerService, CustomerService) 
offspring a b = do 
    split <- getRandomR (1, V.length a) 
    return (mate a b split, mate b a split) 

Cependant quand j'essaye d'appeler cette fonction dans mon action d'étape avec quelque chose comme

(c1,c2) <- offspring p1 p2 

Le compilateur me crie dessus ce type Rand ne me que je suppose que le type FacilityApp correspond pas à attendre ... est logique, mais je ne sais pas comment faire ce travail pour moi.

Je pense que peut-être cela a besoin d'un certain type de levage et de retour? Mais je ne peux pas le comprendre. Quelqu'un peut-il me parler du problème ici?

En tant que question secondaire, notez que j'utilise l'étatT pour tenir mon compteur rond. C'est plus rapide que d'ajouter un argument à l'étape. Existe-t-il un moyen encore plus efficace de prendre soin de cela?

Répondre

3

Votre fonction offspring renvoie un calcul Rand. Rand, cependant, est juste une instance spécifique MonadRandom (est RandT sur Identity), et pas votre monade FacilityApp. Vous devez soit modifier Rand-FacilityApp ou, étant donné que vous utilisez uniquement MonadRandom fonctions, généraliser le type à tout MonadRandom:

offspring :: (MonadRandom m) => CustomerService -> CustomerService 
      -> m (CustomerService, CustomerService) 
Questions connexes