{-# LANGUAGE AllowAmbiguousTypes, TypeApplications #-} -- | Testing the code in the introduction of the paper. module Intro where import Control.Monad import Control.Monad.Credit import Test.Credit import Test.QuickCheck import Data.Tree data Batched a m = Batched [a] [a] deriving (Eq, Ord, Show) rev :: MonadCount m => [a] -> [a] -> m [a] rev [] acc = pure acc rev (x : xs) acc = tick >> rev xs (x : acc) batched :: MonadCount m => [a] -> [a] -> m (Batched a m) batched [] rear = do front <- rev rear [] pure $ Batched front [] batched front rear = pure $ Batched front rear empty :: MonadCount m => m (Batched a m) empty = pure $ Batched [] [] snoc :: MonadCount m => Batched a m -> a -> m (Batched a m) snoc (Batched front rear) x = batched front (x : rear) uncons :: MonadCount m => Batched a m -> m (Maybe (a, Batched a m)) uncons (Batched [] []) = pure Nothing uncons (Batched (x:front) rear) = do q' <- batched front rear pure $ Just (x, q') unfoldM :: Monad m => (b -> m (Maybe (a, b))) -> b -> m [a] unfoldM f b = do mb <- f b case mb of Nothing -> pure [] Just (x, b') -> (x :) <$> unfoldM f b' testBatched :: Either String ([Int], Ticks) testBatched = runCounterM $ empty >>= flip (foldM snoc) [1..10] >>= unfoldM uncons data QueueOp a = Snoc a | Uncons deriving (Eq, Ord, Show) instance Arbitrary a => Arbitrary (QueueOp a) where arbitrary = frequency [ (7, Snoc <$> arbitrary), (3, pure Uncons) ] instance (Arbitrary a, Show a) => DataStructure (Batched a) (QueueOp a) where create = pure $ Batched [] [] perform sz q (Snoc x) = (sz + 1,) <$> snoc q x perform sz q Uncons = do m <- uncons q case m of Nothing -> pure (sz, Batched [] []) Just (_, q') -> pure (sz - 1, q') cost n (Snoc _) = 1 cost n Uncons = 0 testSeq :: IO () testSeq = quickCheck $ checkCredits @(Batched Int) Path genTree :: Strategy -> IO () genTree s = putStrLn . drawTree . fmap show =<< generate (genExecutionTrace @(QueueOp Int) s) testPar :: IO () testPar = quickCheck $ checkCredits @(Batched Int) Random