2017-04-08 13 views
-2

私は州のモナドとキューで遊んでいます。現時点では私は、次のコードを持っている:State Monad Loopを終了

{-# LANGUAGE ViewPatterns, FlexibleContexts #-} 
module Main where 

import Criterion.Main 
import Control.Monad.State.Lazy 
import Data.Maybe (fromJust) 
import Data.Sequence ((<|), ViewR ((:>))) 
import qualified Data.Sequence as S 

-------------------------------------------------------- 
data Queue a = Queue { enqueue :: [a], dequeue :: [a] } 
             deriving (Eq, Show) 
-- adds an item 
push :: a -> Queue a -> Queue a 
push a q = Queue (a:enqueue q) (dequeue q) 

pop :: Queue a -> Maybe (a, Queue a) 
pop q = if null (dequeue q) then 
      go $ Queue [] (reverse (enqueue q)) 
     else 
      go q 
    where go (Queue _ []) = Nothing 
     go (Queue en (x:de)) = Just (x, Queue en de) 

queueTst :: Int -> Queue Int -> Queue Int 
queueTst 0 q = q 
queueTst n q | even n = queueTst (n - 1) (push (100 + n) q) 
      | otherwise = queueTst (n - 1) 
          (if popped == Nothing then q 
          else snd (fromJust popped)) 
    where popped = pop q 
------------------------------------------------------------- 
pushS :: a -> S.Seq a -> S.Seq a 
pushS a s = a <| s 

pushS' :: a -> State (S.Seq a) (Maybe a) 
pushS' a = do 
    s <- get 
    put (a <| s) 
    return Nothing 

pushS'' :: a -> State (S.Seq a) (Maybe a) 
pushS'' a = get >>= (\g -> put (a <| g)) >> return Nothing 

popS :: S.Seq a -> Maybe (a, S.Seq a) 
popS (S.viewr -> S.EmptyR) = Nothing 
popS (S.viewr -> s:>r) = Just (r,s) 

popS' :: State (S.Seq a) (Maybe a) 
popS' = do 
    se <- get 
    let sl = popS'' se 
    put $ snd sl 
    return $ fst sl 
    where popS'' (S.viewr -> S.EmptyR) = (Nothing, S.empty) 
     popS'' (S.viewr -> beg:>r) = (Just r, beg) 

queueTstS :: Int -> S.Seq Int -> S.Seq Int 
queueTstS 0 s = s 
queueTstS n s | even n = queueTstS (n - 1) (pushS (100 + n) s) 
       | otherwise = queueTstS (n - 1) 
          (if popped == Nothing then s 
          else snd (fromJust popped)) 
     where popped = popS s 

queueTstST :: Int -> State (S.Seq Int) (Maybe Int) 
queueTstST n = 
    if (n > 0) then 
    if even n then 
     pushS' (100 + n) >> queueTstST (n - 1) 
    else 
     popS' >> queueTstST (n - 1) 
    else return Nothing 

main :: IO() 
main = defaultMain 
    [ bench "Twin Queue" $ whnf (queueTst 550) (Queue [500,499..1] []) 
    , bench "Sequence Queue" $ whnf (queueTstS 550) (S.fromList [500,499..1]) 
    , bench "State Queue" $ whnf 
        (runState (queueTstST 550)) (S.fromList [500,499..1]) 
    ] 

コードのビットですが、本当にここに関連する唯一の機能はmainqueueTstSTしていること。 queueTstSTを終了する方法はありますが、最後の "Maybe value"を "Nothing"ではなく保持していますか?

答えて

0
queueTstST :: Int -> State (S.Seq Int) (Maybe Int) 
queueTstST n = 
    if (n > 1) then 
    if even n then 
     pushS' (100 + n) >> queueTstST (n - 1) 
    else 
     popS' >> queueTstST (n - 1) 
    else popS' 
+0

これは本当に正解ではありません。 2番目の最後のループがpushS 'だった場合、正解は 'Nothing'になるためです。それがpopS 'ならば、その特定のpopSの 'Just'値であり、これは後続のpopSではありません。 – user1897830

+0

はい - あなたの権利。しかし、最後のループからの値を使ってループを終了する方法があるかどうかは疑問でした。あなたが天気を知らなかった場合、2番目の最後のループはオッズであった。 – user1897830

+0

しかし、もともと、2番目の最後のループは常にpopS 'なので、n = 1であり、ここでは、n = 1ループからの値を返します。 – Gurkenglas

0

あなたは再帰関数に引数を追加する場合は、最後の値を覚えています。

queueTstST :: Int -> State (S.Seq Int) (Maybe Int) 
queueTstST n = go n Nothing 
    where 
    go :: Int -> Maybe Int -> State (S.Seq Int) (Maybe Int) 
    go n v = 
    if (n > 1) 
    then if even n 
     then pushS' (100 + n) >> go (n - 1) Nothing 
     else popS' >>= go (n - 1) 
    else return v 
関連する問題