2017-07-06 4 views
4

ショートバージョン:私はタイプMaybeT (State <type>)()のモナドにrunMaybeT、その後runStateを使用するときに何の状態変化がMaybe結果がJust()に等しいであっても発生しないように、それが見えます。どうして?私のMaybeT(状態<type>)()は状態の変更を無視しますか?

フルバージョン:私はハノイの塔を解決するプログラムを書いています。私がしたかった、そして、

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

:これまでのところ、このプログラムは、正しい出力を生成

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状態を操作、配列を決定し、Stateモナドのリストとして解を表しますプログラムがパズルのルールを尊重していること、つまり小さなディスクの前に大きなディスク(ここでは数値で表される)がないことを確認します。私はすべてのMove後の検証のいくつかの種類を挿入したかったので、私は移動のリストの下の失敗を送信するためにMaybeTモナド変換子を使用しようとしました:

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

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モナドを変更しました

なし状態の変化が発生していないように今の出力は、間違ったになります。

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

私は初期状態を作る場合invali d、確かに検証に失敗します。したがって、Moveの影響が中断されて状態変化がない場合、出力は「violation」という単語になります。

なぜは、runMaybeTを適用した後、(Just(), Towers [1,2,3,4,5] [] [])に等しいrunStateを適用した結果ですか?


ここで参考にしてください。私はlifting the get and put monads in my pop and push functionsを試しましたが、それは同じ出力を生成しました。

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

に相当

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

この行を見

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

が、すべてのxのために、我々はreturn x >> a = aを持って、これ

= map (\_ -> verify) moves 

ですから、破棄動きます。あなたはおそらくreturnの代わりにliftを使用するつもりです。

+0

それはそれを修正し、私を啓発しました。ありがとうございました。 – Alex

関連する問題