2016-12-05 6 views
1

私はMaybe-Stateモナドトランスを実装しようとしており、それを使って単純なスタックマシンを実装しています。 状態モナドの定義は多分正しいはずです。スタックが空の場合、それはそれ以外の場合は、Just <popped stack>を返し、何も返さないようにするためMonadトランス:MaybeT(State Stack)を使用したスタックマシンの実装

pop :: MaybeT (State Stack) Int 

:今、私はポップを実装しようとしています。 これは私がこれまで持っているものです。

pop :: MaybeT (State Stack) Int 
pop = guard True (do (r:rs) <- get 
        put rs 
        return r) 

(もちろんTrueは単なるダミーのプレースホルダです - 今、私は右の他の部分を取得したいために、私は、後で条件を実装します)。

私のコードで何が問題になっていますか?私の理解から、guardは条件付き(True)と関数fをとります。条件が成立する場合は、pure fとなります。私の場合は

pure = MaybeT . return . Just 

は、だから私の関数fはちょうどState Stack Intを返すべきではないのですか?


はここMaybeTStateの私の実装では、完全なコードです:あなたのスタックが空の場合、すべての

import Control.Applicative (Alternative(..)) 
import Control.Monad (liftM, ap, guard) 
import Control.Monad.Trans.Class (MonadTrans(lift)) 

main :: IO() 
main = return() 


-- State Monad 
-------------- 

newtype State s a = MakeState { runState :: s -> (a, s) } 

instance Functor (State s) where 
    fmap = liftM 


instance Applicative (State s) where 
    pure a = MakeState $ \s -> (a, s) 
    (<*>) = ap 

instance Monad (State s) where 
    return a = MakeState $ \s -> (a, s) 
    m >>= k = MakeState $ \s -> let (x, s') = runState m s 
           in runState (k x) s' 

get :: State s s 
get = MakeState $ \s -> (s, s) 

put :: s -> State s() 
put s = MakeState $ \_ -> ((), s) 

modify :: (s -> s) -> State s() 
modify f = MakeState $ \s -> ((), f s) 

-- MaybeT MonadTransformer 
--------------------------- 

newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) } 

instance Monad m => Functor (MaybeT m) where 
    fmap a x = MaybeT $ do e <- runMaybeT x 
          return $ fmap a e 



instance Monad m => Applicative (MaybeT m) where 
    pure  = MaybeT . return . Just 
    (<*>) a b = MaybeT $ do e <- runMaybeT a 
          f <- runMaybeT b 
          return $ e <*> f 

instance Monad m => Monad (MaybeT m) where 
    return = pure 
    a >>= b = MaybeT $ do aa <- runMaybeT a 
          maybe (return Nothing) (runMaybeT . b) aa 


instance Monad m => Alternative (MaybeT m) where 
    empty = MaybeT $ return Nothing 
    a <|> b = MaybeT $ do aa <- runMaybeT a 
         bb <- runMaybeT b 
         return $ aa <|> bb 


instance MonadTrans MaybeT where 
    -- "herwrappen" van het argument 
    lift x = MaybeT $ do r <- x 
         return $ Just r 


-- Stack Manipulation 
--------------------- 

type Stack = [Int] 

-- plaats het argument bovenop de stack 
push :: Int -> State Stack() 
push x = do r <- get 
      put (x:r) 
-- geef de grootte van de stack terug 
size :: State Stack Int 
size = do r <- get 
      return $ length r 

-- neem het eerste element van de stack, als het aanwezig is 
-- (hint: hoogle naar `guard`) 
pop :: MaybeT (State Stack) Int 
pop = guard (True) (do (r:rs) <- get 
         put rs 
         return r) 
+0

エラーは何ですか? 'guard'は' MaybeT(State Stack)Int'を必要とする間に 'MaybeT(State Stack)()'を返します。 – Lee

答えて

2

まず、あなたが理解しておく必要があり、あなたのパターンは失敗します。しかしdo-blockで書くと、fail関数が呼び出されます。 のようにMonad m => MaybeT mに実装されています。つまり、パターンが失敗すると、Nothingが返されます。それはあなたが望むものです。

だから、あなたは次のように行うことができます。

pop :: MaybeT (State Stack) Int 
pop = do r:rs <- get 
     put rs 
     return r 
+1

これは* transformers * 'MaybeT'と* mtl *' State'を使用する場合に有効です。この演習では、OPは自分自身の変圧器を使用しているので、これを使うには、 'get'と' put'(または 'MonadState'を実装する)と' MaybeT'の 'fail'を実装する必要があります。 – duplode

+0

私はそれに注意を払わなかったが、それは適切な発言である。 – freestyle

2

guard 2つの引数を取らない、それだけでBool引数を取ります。あなたはまた、MaybeTにあなたの状態の操作を解除する必要が

pop :: MaybeT (State Stack) Int 
pop = do 
    guard True 
    (r:rs) <- lift get 
    lift $ put rs 
    return r 
1

比較のためには、ここにguardにもfailにどちらも頼らないcruder実装です:

pop :: MaybeT (State Stack) Int 
pop = do 
    stk <- lift get 
    case stk of 
    [] -> empty 
    (r:rs) -> do 
     lift (put rs) 
     return r 

の場合は[]となるので、意図した通りにguardを使用しているか、fail失敗したパターンマッチを利用する(フリースタイルの回答のように)。

関連する問題