2017-07-06 6 views
4

Kurzversion: wenn ich runMaybeT und dann runState auf einer Monade vom Typ verwenden MaybeT (State <type>)(), es sieht aus wie keine Zustandsänderungen auftreten, obwohl das Maybe Ergebnis Just() gleich ist. Warum?Warum ignoriert mein MaybeT (State <type>)() Zustandsänderungen?

Vollversion: Ich schreibe ein Programm, um die Türme von Hanoi zu lösen. Ich vertrete die Lösung als eine Liste von State Monaden, das, wenn sequenziert, einen anfänglichen Towers Zustand manipulieren:

data Towers = Towers [Int] [Int] [Int] 
    deriving (Show) 
type Move = State Towers() 

towerMoves :: Int -> Rod -> Rod -> [Move] 
towerMoves 1 r1 r2 = [pop r1 >>= push r2] 
towerMoves n r1 r2 = topToTemp ++ (towerMoves 1 r1 r2) ++ topToFinal 
    where 
    r3 = other r1 r2 
    topToTemp = towerMoves (n - 1) r1 r3 
    topToFinal = towerMoves (n - 1) r3 r2 

moves = towerMoves 5 First Third 
initTowers = Towers [1,2,3,4,5] [] [] 

main = print $ snd $ runState (sequence_ moves) initTowers 

Bis jetzt dieses Programm erzeugt die korrekte Ausgabe:

Towers [] [] [1,2,3,4,5] 

Dann wollte ich vergewissere dich, dass das Programm die Regeln des Puzzles respektiert, dass nämlich keine größere Scheibe (hier durch Zahlen dargestellt) vor einer kleineren Scheibe steht. Ich wollte eine Art von Überprüfung nach jedem Move einzufügen, so dass ich versuchte, den MaybeT Monade Transformator zu verwenden, um einen Ausfall auf die Liste der Züge zu senden:

verifiedMoves :: [MaybeT (State Towers)()] 
verifiedMoves = map ((>> verify) . return) moves 
    where 
    check :: [Int] -> Bool 
    check [] = True 
    check [_] = True 
    check (x:y:ys) = (x < y) && check (y:ys) 
    verify :: MaybeT (State Towers)() 
    verify = do 
     (Towers xs ys zs) <- lift get 
     guard (check xs && check ys && check zs) 

Dementsprechend änderte ich die main Monade:

main = maybe (putStrLn "violation") (const $ print finalTowers) v 
    where 
    (v, finalTowers) = runState (runMaybeT $ sequence_ verifiedMoves) initTowers 

Jetzt sieht die Ausgabe falsch, wie keine Zustandsänderungen aufgetreten:

Towers [1,2,3,4,5] [] [] 

Wenn ich den Anfangszustand invali machen d, es versäumt in der Tat die Überprüfung. Wenn es also keine Zustandsänderung gibt, weil die Auswirkungen der s unterbrochen wurden, würde ich erwarten, dass die Ausgabe das Wort "Verletzung" sein würde.

Warum nach runMaybeT angewendet wird, ist das Ergebnis von runState gleich (Just(), Towers [1,2,3,4,5] [] []) Anwendung?


Hier ist der Rest des Codes, als Referenz. Ich habe versucht lifting the get and put monads in my pop and push functions, aber das produzierte die gleiche Ausgabe.

import Control.Monad 
import Data.Functor.Identity 
import Control.Monad.State 
import Control.Monad.Trans.Maybe 
import qualified Data.Map as M 

data Rod = First | Second | Third 
    deriving (Show) 

other :: Rod -> Rod -> Rod 
other First Second = Third 
other Second First = Third 
other First Third = Second 
other Third First = Second 
other Second Third = First 
other Third Second = First 

getRod :: Towers -> Rod -> [Int] 
getRod (Towers x y z) First = x 
getRod (Towers x y z) Second = y 
getRod (Towers x y z) Third = z 

setRod :: Rod -> Towers -> [Int] -> Towers 
setRod First t ds = Towers ds r2 r3 
    where 
    r2 = t `getRod` Second 
    r3 = t `getRod` Third 
setRod Second t ds = Towers r1 ds r3 
    where 
    r1 = t `getRod` First 
    r3 = t `getRod` Third 
setRod Third t ds = Towers r1 r2 ds 
    where 
    r1 = t `getRod` First 
    r2 = t `getRod` Second 

pop :: Rod -> State Towers Int 
pop r = do 
    t <- get 
    let ds = t `getRod` r 
     d = head ds 
     load = setRod r 
    put $ t `load` (tail ds) 
    return d 

push :: Rod -> Int -> State Towers() 
push r d = do 
    t <- get 
    let ds = t `getRod` r 
     load = setRod r 
    put $ t `load` (d:ds) 

Antwort

9

Schauen Sie sich diese Linie

verifiedMoves = map ((>> verify) . return) moves 

entspricht

= map (\m -> return m >> verify) moves 

sondern für alle x, haben wir return x >> a = a, so

= map (\_ -> verify) moves 

So verworfen Sie die bewegt sich. Sie wollten wahrscheinlich lift anstelle von return dort verwenden.

+0

Das reparierte es und erleuchtete mich. Vielen Dank. – Alex

Verwandte Themen