packages feed

creditmonad-1.1.0: src/Test/Credit/Deque/Base.hs

{-# LANGUAGE AllowAmbiguousTypes, TypeApplications #-}

module Test.Credit.Deque.Base (DequeOp(..), Deque(..), BoundedDeque(..), D, BD) where

import Prelude hiding (concat)
import Control.Monad.Credit
import Test.Credit
import Test.QuickCheck

data DequeOp a = Cons a | Snoc a | Uncons | Unsnoc | Concat
  deriving (Eq, Ord, Show)

instance Arbitrary a => Arbitrary (DequeOp a) where
  arbitrary = frequency
    [ (7, Cons <$> arbitrary)
    , (4, Snoc <$> arbitrary)
    , (2, pure Uncons)
    , (6, pure Unsnoc)
    , (1, pure Concat)
    ]

class Deque q where
  empty :: MonadLazy m => m (q a m)
  cons :: MonadInherit m => a -> q a m -> m (q a m)
  snoc :: MonadInherit m => q a m -> a -> m (q a m)
  uncons :: MonadInherit m => q a m -> m (Maybe (a, q a m))
  unsnoc :: MonadInherit m => q a m -> m (Maybe (q a m, a))
  concat :: MonadInherit m => q a m -> q a m -> m (q a m)

class Deque q => BoundedDeque q where
  qcost :: Size -> DequeOp a -> Credit

data D q a m = D (q (PrettyCell a) m)

instance (MemoryCell m (q (PrettyCell a) m)) => MemoryCell m (D q a m) where
  prettyCell (D q) = prettyCell q

instance (MemoryStructure (q (PrettyCell a))) => MemoryStructure (D q a) where
  prettyStructure (D q) = prettyStructure q


instance (Arbitrary a, BoundedDeque q, Show a) => DataStructure (D q a) (DequeOp a) where
  cost _ Concat = 0
  cost sz op = qcost @q sz op
  create = D <$> empty
  perform sz (D q) (Cons x) = (sz + 1,) <$> D <$> cons (PrettyCell x) q
  perform sz (D q) (Snoc x) = (sz + 1,) <$> D <$> snoc q (PrettyCell x)
  perform sz (D q) Uncons = do
    m <- uncons q
    case m of
      Nothing -> (sz,) <$> D <$> empty
      Just (_, q') -> pure (sz - 1, D q')
  perform sz (D q) Unsnoc = do
    m <- unsnoc q
    case m of
      Nothing -> (sz,) <$> D <$> empty
      Just (q', _) -> pure (sz - 1, D q')
  perform sz (D q) Concat = pure $ (sz, D q) -- no op

data BD q a m = BD (D q a m) (D q a m)

instance (MemoryCell m (q (PrettyCell a) m)) => MemoryCell m (BD q a m) where
  prettyCell (BD q1 q2) = do
    q1' <- prettyCell q1
    q2' <- prettyCell q2
    pure $ mkMCell "Concat" [q1', q2']

instance (MemoryStructure (q (PrettyCell a))) => MemoryStructure (BD q a) where
  prettyStructure (BD q1 q2) = do
    q1' <- prettyStructure q1
    q2' <- prettyStructure q2
    pure $ mkMCell "Concat" [q1', q2']

instance (Arbitrary a, BoundedDeque q, Show a) => DataStructure (BD q a) (DequeOp a) where
  cost = qcost @q
  create = do
    q1 <- empty
    q2 <- empty
    pure $ BD (D q1) (D q2)
  perform sz (BD q1 q2) (Cons x) = do
    (sz, q1) <- perform sz q1 (Cons x)
    pure (sz, BD q1 q2)
  perform sz (BD q1 q2) (Snoc x) = do
    (sz, q2) <- perform sz q2 (Snoc x)
    pure (sz, BD q1 q2)
  perform sz (BD q1 q2) Uncons = do
    (sz, q1) <- perform sz q1 Uncons
    pure (sz, BD q1 q2)
  perform sz (BD q1 q2) Unsnoc = do
    (sz, q2) <- perform sz q2 Unsnoc
    pure (sz, BD q1 q2)
  perform sz (BD (D q1) (D q2)) Concat = do
    e <- empty
    q <- concat q1 q2
    pure (sz, BD (D e) (D q))