2017-07-06 91 views
4

短版:当我在MaybeT (State <type>)()类型的单子使用runMaybeT然后runState,它看起来即使Maybe结果等于Just()像没有发生状态变化。为什么?为什么我的MaybeT(状态<type>)()忽略状态更改?

完整版本:我在写一个程序来解决河内的塔。我所代表的溶液作为State单子列表是,测序时,操纵初始Towers状态:

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 

迄今为止,这种方案产生正确的输出:

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

然后,我想验证该程序是否遵守该难题的规则,即在较小的光盘之前没有更大的光盘(以数字表示)出现。我想每一个Move后插入某种验证的,所以我试图用MaybeT单子转换到发送失败向下的动作列表:

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) 

因此我改变了main单子:

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

现在输出看起来不对劲,好像没有发生任何状态变化:

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

如果我让初始状态invali d,它的确没有通过验证。因此,如果由于Move的影响被打断而没有状态变化,我希望输出成为“违规”一词。

为什么,应用runMaybeT后,是将runState等于(Just(), Towers [1,2,3,4,5] [] [])的结果呢?


以下是其余代码,供参考。我试过lifting the get and put monads in my pop and push functions,但是生成了相同的输出。

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) 

回答

9

看这句话相当于

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

而且对所有x

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

,我们有return x >> a = a,从而

= map (\_ -> verify) moves 

所以,你丢弃移动。您可能打算在那里使用lift而不是return

+0

修复它并启发我。谢谢。 – Alex

相关问题