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)
Das reparierte es und erleuchtete mich. Vielen Dank. – Alex