packages feed

deque 0.2.7 → 0.3

raw patch · 9 files changed

+1052/−244 lines, 9 filesdep +mtlPVP ok

version bump matches the API change (PVP)

Dependencies added: mtl

API changes (from Hackage documentation)

- Deque: Deque :: [a] -> [a] -> Deque a
- Deque: cons :: a -> Deque a -> Deque a
- Deque: data Deque a
- Deque: dropWhile :: (a -> Bool) -> Deque a -> Deque a
- Deque: fromList :: [a] -> Deque a
- Deque: head :: Deque a -> Maybe a
- Deque: init :: Deque a -> Deque a
- Deque: instance Control.Monad.Fail.MonadFail Deque.Deque
- Deque: instance Data.Foldable.Foldable Deque.Deque
- Deque: instance Data.Traversable.Traversable Deque.Deque
- Deque: instance GHC.Base.Alternative Deque.Deque
- Deque: instance GHC.Base.Applicative Deque.Deque
- Deque: instance GHC.Base.Functor Deque.Deque
- Deque: instance GHC.Base.Monad Deque.Deque
- Deque: instance GHC.Base.MonadPlus Deque.Deque
- Deque: instance GHC.Base.Monoid (Deque.Deque a)
- Deque: instance GHC.Base.Semigroup (Deque.Deque a)
- Deque: instance GHC.Classes.Eq a => GHC.Classes.Eq (Deque.Deque a)
- Deque: instance GHC.Show.Show a => GHC.Show.Show (Deque.Deque a)
- Deque: last :: Deque a -> Maybe a
- Deque: null :: Deque a -> Bool
- Deque: prepend :: Deque a -> Deque a -> Deque a
- Deque: reverse :: Deque a -> Deque a
- Deque: shiftLeft :: Deque a -> Deque a
- Deque: shiftRight :: Deque a -> Deque a
- Deque: snoc :: a -> Deque a -> Deque a
- Deque: tail :: Deque a -> Deque a
- Deque: takeWhile :: (a -> Bool) -> Deque a -> Deque a
- Deque: uncons :: Deque a -> Maybe (a, Deque a)
- Deque: unsnoc :: Deque a -> Maybe (a, Deque a)
+ Deque.Lazy: cons :: a -> Deque a -> Deque a
+ Deque.Lazy: data Deque a
+ Deque.Lazy: dropWhile :: (a -> Bool) -> Deque a -> Deque a
+ Deque.Lazy: filter :: (a -> Bool) -> Deque a -> Deque a
+ Deque.Lazy: fromConsAndSnocLists :: [a] -> [a] -> Deque a
+ Deque.Lazy: head :: Deque a -> Maybe a
+ Deque.Lazy: init :: Deque a -> Deque a
+ Deque.Lazy: instance Control.Monad.Fail.MonadFail Deque.Lazy.Deque
+ Deque.Lazy: instance Data.Foldable.Foldable Deque.Lazy.Deque
+ Deque.Lazy: instance Data.Traversable.Traversable Deque.Lazy.Deque
+ Deque.Lazy: instance GHC.Base.Alternative Deque.Lazy.Deque
+ Deque.Lazy: instance GHC.Base.Applicative Deque.Lazy.Deque
+ Deque.Lazy: instance GHC.Base.Functor Deque.Lazy.Deque
+ Deque.Lazy: instance GHC.Base.Monad Deque.Lazy.Deque
+ Deque.Lazy: instance GHC.Base.MonadPlus Deque.Lazy.Deque
+ Deque.Lazy: instance GHC.Base.Monoid (Deque.Lazy.Deque a)
+ Deque.Lazy: instance GHC.Base.Semigroup (Deque.Lazy.Deque a)
+ Deque.Lazy: instance GHC.Classes.Eq a => GHC.Classes.Eq (Deque.Lazy.Deque a)
+ Deque.Lazy: instance GHC.Exts.IsList (Deque.Lazy.Deque a)
+ Deque.Lazy: instance GHC.Show.Show a => GHC.Show.Show (Deque.Lazy.Deque a)
+ Deque.Lazy: last :: Deque a -> Maybe a
+ Deque.Lazy: null :: Deque a -> Bool
+ Deque.Lazy: reverse :: Deque a -> Deque a
+ Deque.Lazy: shiftLeft :: Deque a -> Deque a
+ Deque.Lazy: shiftRight :: Deque a -> Deque a
+ Deque.Lazy: snoc :: a -> Deque a -> Deque a
+ Deque.Lazy: tail :: Deque a -> Deque a
+ Deque.Lazy: takeWhile :: (a -> Bool) -> Deque a -> Deque a
+ Deque.Lazy: uncons :: Deque a -> Maybe (a, Deque a)
+ Deque.Lazy: unsnoc :: Deque a -> Maybe (a, Deque a)
+ Deque.Lazy.State: cons :: MonadState (Deque a) m => a -> m ()
+ Deque.Lazy.State: dropWhile :: MonadState (Deque a) m => (a -> Bool) -> m ()
+ Deque.Lazy.State: filter :: MonadState (Deque a) m => (a -> Bool) -> m ()
+ Deque.Lazy.State: head :: MonadState (Deque a) m => m (Maybe a)
+ Deque.Lazy.State: init :: MonadState (Deque a) m => m (Deque a)
+ Deque.Lazy.State: last :: MonadState (Deque a) m => m (Maybe a)
+ Deque.Lazy.State: length :: MonadState (Deque a) m => m Int
+ Deque.Lazy.State: null :: MonadState (Deque a) m => m Bool
+ Deque.Lazy.State: reverse :: MonadState (Deque a) m => m ()
+ Deque.Lazy.State: shiftLeft :: MonadState (Deque a) m => m ()
+ Deque.Lazy.State: shiftRight :: MonadState (Deque a) m => m ()
+ Deque.Lazy.State: snoc :: MonadState (Deque a) m => a -> m ()
+ Deque.Lazy.State: tail :: MonadState (Deque a) m => m (Deque a)
+ Deque.Lazy.State: takeWhile :: MonadState (Deque a) m => (a -> Bool) -> m ()
+ Deque.Lazy.State: uncons :: MonadState (Deque a) m => m (Maybe a)
+ Deque.Lazy.State: unsnoc :: MonadState (Deque a) m => m (Maybe a)
+ Deque.Strict: cons :: a -> Deque a -> Deque a
+ Deque.Strict: data Deque a
+ Deque.Strict: dropWhile :: (a -> Bool) -> Deque a -> Deque a
+ Deque.Strict: filter :: (a -> Bool) -> Deque a -> Deque a
+ Deque.Strict: fromConsAndSnocLists :: [a] -> [a] -> Deque a
+ Deque.Strict: head :: Deque a -> Maybe a
+ Deque.Strict: init :: Deque a -> Deque a
+ Deque.Strict: instance Control.Monad.Fail.MonadFail Deque.Strict.Deque
+ Deque.Strict: instance Data.Foldable.Foldable Deque.Strict.Deque
+ Deque.Strict: instance Data.Traversable.Traversable Deque.Strict.Deque
+ Deque.Strict: instance GHC.Base.Alternative Deque.Strict.Deque
+ Deque.Strict: instance GHC.Base.Applicative Deque.Strict.Deque
+ Deque.Strict: instance GHC.Base.Functor Deque.Strict.Deque
+ Deque.Strict: instance GHC.Base.Monad Deque.Strict.Deque
+ Deque.Strict: instance GHC.Base.MonadPlus Deque.Strict.Deque
+ Deque.Strict: instance GHC.Base.Monoid (Deque.Strict.Deque a)
+ Deque.Strict: instance GHC.Base.Semigroup (Deque.Strict.Deque a)
+ Deque.Strict: instance GHC.Classes.Eq a => GHC.Classes.Eq (Deque.Strict.Deque a)
+ Deque.Strict: instance GHC.Exts.IsList (Deque.Strict.Deque a)
+ Deque.Strict: instance GHC.Show.Show a => GHC.Show.Show (Deque.Strict.Deque a)
+ Deque.Strict: last :: Deque a -> Maybe a
+ Deque.Strict: null :: Deque a -> Bool
+ Deque.Strict: reverse :: Deque a -> Deque a
+ Deque.Strict: shiftLeft :: Deque a -> Deque a
+ Deque.Strict: shiftRight :: Deque a -> Deque a
+ Deque.Strict: snoc :: a -> Deque a -> Deque a
+ Deque.Strict: tail :: Deque a -> Deque a
+ Deque.Strict: takeWhile :: (a -> Bool) -> Deque a -> Deque a
+ Deque.Strict: uncons :: Deque a -> Maybe (a, Deque a)
+ Deque.Strict: unsnoc :: Deque a -> Maybe (a, Deque a)
+ Deque.Strict.State: cons :: MonadState (Deque a) m => a -> m ()
+ Deque.Strict.State: dropWhile :: MonadState (Deque a) m => (a -> Bool) -> m ()
+ Deque.Strict.State: filter :: MonadState (Deque a) m => (a -> Bool) -> m ()
+ Deque.Strict.State: head :: MonadState (Deque a) m => m (Maybe a)
+ Deque.Strict.State: init :: MonadState (Deque a) m => m (Deque a)
+ Deque.Strict.State: last :: MonadState (Deque a) m => m (Maybe a)
+ Deque.Strict.State: length :: MonadState (Deque a) m => m Int
+ Deque.Strict.State: null :: MonadState (Deque a) m => m Bool
+ Deque.Strict.State: reverse :: MonadState (Deque a) m => m ()
+ Deque.Strict.State: shiftLeft :: MonadState (Deque a) m => m ()
+ Deque.Strict.State: shiftRight :: MonadState (Deque a) m => m ()
+ Deque.Strict.State: snoc :: MonadState (Deque a) m => a -> m ()
+ Deque.Strict.State: tail :: MonadState (Deque a) m => m (Deque a)
+ Deque.Strict.State: takeWhile :: MonadState (Deque a) m => (a -> Bool) -> m ()
+ Deque.Strict.State: uncons :: MonadState (Deque a) m => m (Maybe a)
+ Deque.Strict.State: unsnoc :: MonadState (Deque a) m => m (Maybe a)

Files

deque.cabal view
@@ -1,9 +1,9 @@ name: deque-version: 0.2.7-synopsis: Double-ended queue+version: 0.3+synopsis: Double-ended queues description:-  An implementation of Double-Ended Queue (aka Dequeue or Deque)-  based on the head-tail linked list.+  Strict and lazy implementations of Double-Ended Queue (aka Dequeue or Deque)+  based on head-tail linked list. homepage: https://github.com/nikita-volkov/deque bug-reports: https://github.com/nikita-volkov/deque/issues author: Nikita Volkov <nikita.y.volkov@mail.ru>@@ -20,17 +20,24 @@  library   hs-source-dirs: library-  default-extensions: DeriveFunctor, ScopedTypeVariables, StandaloneDeriving+  default-extensions: BangPatterns, DeriveDataTypeable, DeriveGeneric, DeriveFunctor, DeriveTraversable, FlexibleContexts, FlexibleInstances, LambdaCase, NoImplicitPrelude, RankNTypes, ScopedTypeVariables, StandaloneDeriving, TypeApplications, TypeFamilies   default-language: Haskell2010   exposed-modules:-    Deque+    Deque.Lazy+    Deque.Lazy.State+    Deque.Strict+    Deque.Strict.State+  other-modules:+    Deque.Prelude+    Deque.StrictList   build-depends:-    base >= 4.9 && < 5+    base >=4.9 && <5,+    mtl >=2.2 && <3  test-suite test   type: exitcode-stdio-1.0   hs-source-dirs: test-  default-extensions: DeriveFunctor, ScopedTypeVariables, StandaloneDeriving+  default-extensions: BangPatterns, DeriveDataTypeable, DeriveGeneric, DeriveFunctor, DeriveTraversable, FlexibleContexts, FlexibleInstances, LambdaCase, NoImplicitPrelude, RankNTypes, ScopedTypeVariables, StandaloneDeriving, TypeApplications, TypeFamilies   default-language: Haskell2010   main-is:     Main.hs
− library/Deque.hs
@@ -1,216 +0,0 @@-module Deque where--import Prelude hiding (foldr, foldr', foldl')-import Control.Applicative-import Control.Monad-import Control.Monad.Fail-import Data.Foldable-import Data.Traversable-import Data.Maybe-import Data.Monoid hiding ((<>))-import Data.Semigroup-import qualified Data.List as List---- |--- Double-ended queue (aka Dequeue or Deque) based on the head-tail linked list.--- Can be cycled. See `shiftLeft` and `shiftRight`.-data Deque a =-  Deque [a] [a]---- |--- /O(1)/.--- `toList` is available from the `Foldable` instance.-fromList :: [a] -> Deque a-fromList =-  Deque []---- |--- /O(n)/.--- Leave only the first elements satisfying the predicate.-takeWhile :: (a -> Bool) -> Deque a -> Deque a-takeWhile predicate (Deque snocList consList) =-  let-    newConsList = List.foldr-      (\ a nextState -> if predicate a-        then a : nextState-        else [])-      (List.takeWhile predicate (List.reverse snocList))-      consList-    in Deque [] newConsList---- |--- /O(n)/.--- Drop the first elements satisfying the predicate.-dropWhile :: (a -> Bool) -> Deque a -> Deque a-dropWhile predicate (Deque snocList consList) =-  let-    newConsList = List.dropWhile predicate consList-    in case newConsList of-      [] -> Deque [] (List.dropWhile predicate (List.reverse snocList))-      _ -> Deque snocList newConsList---- |--- /O(1)/, occasionally /O(n)/.------ @--- λ toList . shiftLeft $ fromList [1,2,3]--- [2,3,1]--- @-shiftLeft :: Deque a -> Deque a-shiftLeft deque =-  maybe deque (uncurry snoc) (uncons deque)---- |--- /O(1)/, occasionally /O(n)/.------ @--- λ toList . shiftRight $ fromList [1,2,3]--- [3,1,2]--- @-shiftRight :: Deque a -> Deque a-shiftRight deque =-  maybe deque (uncurry cons) (unsnoc deque)---- |--- /O(1)/.--- Prepend an element.-cons :: a -> Deque a -> Deque a-cons a (Deque snocList consList) =-  Deque snocList (a : consList)---- |--- /O(1)/.--- Append an element.-snoc :: a -> Deque a -> Deque a-snoc a (Deque snocList consList) =-  Deque (a : snocList) consList---- |--- /O(1)/, occasionally /O(n)/.-uncons :: Deque a -> Maybe (a, Deque a)-uncons (Deque snocList consList) =-  case consList of-    head : tail ->-      Just (head, Deque snocList tail)-    _ ->-      case Prelude.reverse snocList of-        head : tail ->-          Just (head, Deque [] tail)-        _ ->-          Nothing---- |--- /O(1)/, occasionally /O(n)/.-unsnoc :: Deque a -> Maybe (a, Deque a)-unsnoc (Deque snocList consList) =-  case snocList of-    head : tail ->-      Just (head, Deque tail consList)-    _ ->-      case Prelude.reverse consList of-        head : tail ->-          Just (head, Deque tail [])-        _ ->-          Nothing---- |--- /O(n)/.-prepend :: Deque a -> Deque a -> Deque a-prepend (Deque snocList1 consList1) (Deque snocList2 consList2) =-  Deque snocList3 consList3-  where-    snocList3 =-      snocList2 ++ foldl' (flip (:)) snocList1 consList2-    consList3 =-      consList1---- |--- /O(1)/.-reverse :: Deque a -> Deque a-reverse (Deque snocList consList) =-  Deque consList snocList---- |--- /O(1)/. -null :: Deque a -> Bool-null (Deque snocList consList) =-  List.null snocList && List.null consList---- |--- /O(1)/, occasionally /O(n)/.-head :: Deque a -> Maybe a-head =-  fmap fst . uncons---- |--- /O(1)/, occasionally /O(n)/.-tail :: Deque a -> Deque a-tail =-  fromMaybe <$> id <*> fmap snd . uncons---- |--- /O(1)/, occasionally /O(n)/.-init :: Deque a -> Deque a-init =-  fromMaybe <$> id <*> fmap snd . unsnoc---- |--- /O(1)/, occasionally /O(n)/.-last :: Deque a -> Maybe a-last =-  fmap fst . unsnoc---deriving instance Eq a => Eq (Deque a)--deriving instance Show a => Show (Deque a)--instance Semigroup (Deque a) where-  (<>) = prepend--instance Monoid (Deque a) where-  mempty =-    Deque [] []-  mappend =-    (<>)--instance Foldable Deque where-  foldr step init (Deque snocList consList) =-    foldr step (foldl' (flip step) init snocList) consList-  foldl' step init (Deque snocList consList) =-    foldr' (flip step) (foldl' step init consList) snocList--instance Traversable Deque where-  traverse f (Deque ss cs) =-    (\cs' ss' -> Deque (Prelude.reverse ss') cs') <$> traverse f cs <*> traverse f (Prelude.reverse ss)--deriving instance Functor Deque--instance Applicative Deque where-  pure a =-    Deque [] [a]-  fs <*> as =-    fromList (toList fs <*> toList as)--instance Monad Deque where-  return =-    pure-  m >>= f =-    fromList (toList m >>= toList . f)-  fail =-    const mempty--instance Alternative Deque where-  empty =-    mempty-  (<|>) =-    mappend--instance MonadPlus Deque where-  mzero =-    empty-  mplus =-    (<|>)--instance MonadFail Deque where-  fail = const mempty
+ library/Deque/Lazy.hs view
@@ -0,0 +1,226 @@+{-|+Definitions of lazy Deque.++The typical `toList` and `fromList` conversions are provided by means of+the `Foldable` and `IsList` instances.+-}+module Deque.Lazy+(+  Deque,+  fromConsAndSnocLists,+  cons,+  snoc,+  reverse,+  shiftLeft,+  shiftRight,+  filter,+  takeWhile,+  dropWhile,+  uncons,+  unsnoc,+  null,+  head,+  last,+  tail,+  init,+)+where++import Control.Monad (fail)+import Deque.Prelude hiding (tail, init, last, head, null, dropWhile, takeWhile, reverse, filter)+import qualified Data.List as List+import qualified Deque.Prelude as Prelude++-- |+-- Lazy double-ended queue (aka Dequeue or Deque) based on head-tail linked list.+data Deque a = Deque {-# UNPACK #-} ![a] {-# UNPACK #-} ![a]++-- |+-- /O(1)/.+-- Construct from cons and snoc lists.+fromConsAndSnocLists :: [a] -> [a] -> Deque a+fromConsAndSnocLists consList snocList = Deque snocList consList++-- |+-- /O(n)/.+-- Leave only the elements satisfying the predicate.+filter :: (a -> Bool) -> Deque a -> Deque a+filter predicate (Deque snocList consList) = Deque (List.filter predicate snocList) (List.filter predicate consList)++-- |+-- /O(n)/.+-- Leave only the first elements satisfying the predicate.+takeWhile :: (a -> Bool) -> Deque a -> Deque a+takeWhile predicate (Deque snocList consList) = let+  newConsList = List.foldr+    (\ a nextState -> if predicate a+      then a : nextState+      else [])+    (List.takeWhile predicate (List.reverse snocList))+    consList+  in Deque [] newConsList++-- |+-- /O(n)/.+-- Drop the first elements satisfying the predicate.+dropWhile :: (a -> Bool) -> Deque a -> Deque a+dropWhile predicate (Deque snocList consList) = let+  newConsList = List.dropWhile predicate consList+  in case newConsList of+    [] -> Deque [] (List.dropWhile predicate (List.reverse snocList))+    _ -> Deque snocList newConsList++-- |+-- /O(1)/, occasionally /O(n)/.+-- Move the first element to the end.+--+-- @+-- λ toList . shiftLeft $ fromList [1,2,3]+-- [2,3,1]+-- @+shiftLeft :: Deque a -> Deque a+shiftLeft deque = maybe deque (uncurry snoc) (uncons deque)++-- |+-- /O(1)/, occasionally /O(n)/.+-- Move the last element to the beginning.+--+-- @+-- λ toList . shiftRight $ fromList [1,2,3]+-- [3,1,2]+-- @+shiftRight :: Deque a -> Deque a+shiftRight deque = maybe deque (uncurry cons) (unsnoc deque)++-- |+-- /O(1)/.+-- Add element in the beginning.+cons :: a -> Deque a -> Deque a+cons a (Deque snocList consList) = Deque snocList (a : consList)++-- |+-- /O(1)/.+-- Add element in the ending.+snoc :: a -> Deque a -> Deque a+snoc a (Deque snocList consList) = Deque (a : snocList) consList++-- |+-- /O(1)/, occasionally /O(n)/.+-- Get the first element and deque without it if it's not empty.+uncons :: Deque a -> Maybe (a, Deque a)+uncons (Deque snocList consList) = case consList of+  head : tail -> Just (head, Deque snocList tail)+  _ -> case List.reverse snocList of+    head : tail -> Just (head, Deque [] tail)+    _ -> Nothing++-- |+-- /O(1)/, occasionally /O(n)/.+-- Get the last element and deque without it if it's not empty.+unsnoc :: Deque a -> Maybe (a, Deque a)+unsnoc (Deque snocList consList) = case snocList of+  head : tail -> Just (head, Deque tail consList)+  _ -> case List.reverse consList of+    head : tail -> Just (head, Deque tail [])+    _ -> Nothing++-- |+-- /O(n)/.+prepend :: Deque a -> Deque a -> Deque a+prepend (Deque snocList1 consList1) (Deque snocList2 consList2) = Deque snocList3 consList3 where+  snocList3 = snocList2 ++ foldl' (flip (:)) snocList1 consList2+  consList3 = consList1++-- |+-- /O(1)/.+-- Revert the deque.+reverse :: Deque a -> Deque a+reverse (Deque snocList consList) = Deque consList snocList++-- |+-- /O(1)/. +-- Check whether deque is empty.+null :: Deque a -> Bool+null (Deque snocList consList) = List.null snocList && List.null consList++-- |+-- /O(1)/, occasionally /O(n)/.+-- Get the first element if deque is not empty.+head :: Deque a -> Maybe a+head = fmap fst . uncons++-- |+-- /O(1)/, occasionally /O(n)/.+-- Keep all elements but the first one.+-- +-- In case of empty deque returns an empty deque.+tail :: Deque a -> Deque a+tail = fromMaybe <$> id <*> fmap snd . uncons++-- |+-- /O(1)/, occasionally /O(n)/.+-- Keep all elements but the last one.+-- +-- In case of empty deque returns an empty deque.+init :: Deque a -> Deque a+init = fromMaybe <$> id <*> fmap snd . unsnoc++-- |+-- /O(1)/, occasionally /O(n)/.+-- Get the last element if deque is not empty.+last :: Deque a -> Maybe a+last = fmap fst . unsnoc+++instance Eq a => Eq (Deque a) where+  (==) a b = toList a == toList b++instance Show a => Show (Deque a) where+  show = showString "fromList " . show . toList++instance Semigroup (Deque a) where+  (<>) = prepend++instance Monoid (Deque a) where+  mempty =+    Deque [] []+  mappend =+    (<>)++instance Foldable Deque where+  foldr step init (Deque snocList consList) = foldr step (foldl' (flip step) init snocList) consList+  foldl' step init (Deque snocList consList) = foldr' (flip step) (foldl' step init consList) snocList++instance Traversable Deque where+  traverse f (Deque ss cs) =+    (\cs' ss' -> Deque (List.reverse ss') cs') <$> traverse f cs <*> traverse f (List.reverse ss)++deriving instance Functor Deque++instance Applicative Deque where+  pure a = Deque [] [a]+  fs <*> as = fromList (toList fs <*> toList as)++instance Monad Deque where+  return = pure+  m >>= f = fromList (toList m >>= toList . f)+  fail = const mempty++instance Alternative Deque where+  empty = mempty+  (<|>) = mappend++instance MonadPlus Deque where+  mzero = empty+  mplus = (<|>)++instance MonadFail Deque where+  fail = const mempty++-- |+-- /O(1)/.+instance IsList (Deque a) where+  type Item (Deque a) = a+  fromList = Deque []+  toList (Deque snocList consList) = consList <> List.reverse snocList+  
+ library/Deque/Lazy/State.hs view
@@ -0,0 +1,115 @@+{-|+Lazy Deque API lifted to a State monad, \"mtl\"-style.+-}+module Deque.Lazy.State+where++import Deque.Prelude hiding (tail, init, last, head, null, dropWhile, takeWhile, reverse)+import Deque.Lazy (Deque)+import qualified Deque.Lazy as Deque+import qualified Deque.Prelude as Prelude+++-- |+-- /O(1)/.+-- Add element in the beginning.+cons :: MonadState (Deque a) m => a -> m ()+cons a = modify (Deque.cons a)++-- |+-- /O(1)/.+-- Add element in the ending.+snoc :: MonadState (Deque a) m => a -> m ()+snoc a = modify (Deque.snoc a)++-- |+-- /O(1)/.+-- Revert the deque.+reverse :: MonadState (Deque a) m => m ()+reverse = modify Deque.reverse++-- |+-- /O(1)/, occasionally /O(n)/.+-- Move the first element to the end.+shiftLeft :: MonadState (Deque a) m => m ()+shiftLeft = modify Deque.shiftLeft++-- |+-- /O(1)/, occasionally /O(n)/.+-- Move the last element to the beginning.+shiftRight :: MonadState (Deque a) m => m ()+shiftRight = modify Deque.shiftRight++-- |+-- /O(n)/.+-- Leave only the elements satisfying the predicate.+filter :: MonadState (Deque a) m => (a -> Bool) -> m ()+filter predicate = modify (Deque.filter predicate)++-- |+-- /O(n)/.+-- Leave only the first elements satisfying the predicate.+takeWhile :: MonadState (Deque a) m => (a -> Bool) -> m ()+takeWhile predicate = modify (Deque.takeWhile predicate)++-- |+-- /O(n)/.+-- Drop the first elements satisfying the predicate.+dropWhile :: MonadState (Deque a) m => (a -> Bool) -> m ()+dropWhile predicate = modify (Deque.dropWhile predicate)++-- |+-- /O(1)/, occasionally /O(n)/.+-- Get the first element and deque without it if it's not empty.+uncons :: MonadState (Deque a) m => m (Maybe a)+uncons = state (\ deque -> case Deque.uncons deque of+  Nothing -> (Nothing, deque)+  Just (a, newDeque) -> (Just a, newDeque))++-- |+-- /O(1)/, occasionally /O(n)/.+-- Get the last element and deque without it if it's not empty.+unsnoc :: MonadState (Deque a) m => m (Maybe a)+unsnoc = state (\ deque -> case Deque.unsnoc deque of+  Nothing -> (Nothing, deque)+  Just (a, newDeque) -> (Just a, newDeque))++-- |+-- /O(1)/. +-- Check whether deque is empty.+null :: MonadState (Deque a) m => m Bool+null = gets Deque.null++-- |+-- /O(1)/. +-- Check whether deque is empty.+length :: MonadState (Deque a) m => m Int+length = gets Prelude.length++-- |+-- /O(1)/, occasionally /O(n)/.+-- Get the first element if deque is not empty.+head :: MonadState (Deque a) m => m (Maybe a)+head = gets Deque.head++-- |+-- /O(1)/, occasionally /O(n)/.+-- Get the last element if deque is not empty.+last :: MonadState (Deque a) m => m (Maybe a)+last = gets Deque.last++-- |+-- /O(1)/, occasionally /O(n)/.+-- Keep all elements but the first one.+-- +-- In case of empty deque returns an empty deque.+tail :: MonadState (Deque a) m => m (Deque a)+tail = gets Deque.tail++-- |+-- /O(1)/, occasionally /O(n)/.+-- Keep all elements but the last one.+-- +-- In case of empty deque returns an empty deque.+init :: MonadState (Deque a) m => m (Deque a)+init = gets Deque.init
+ library/Deque/Prelude.hs view
@@ -0,0 +1,78 @@+module Deque.Prelude+(+  module Exports,+)+where+++-- base+-------------------------+import Control.Applicative as Exports+import Control.Arrow as Exports+import Control.Category as Exports+import Control.Concurrent as Exports+import Control.Exception as Exports+import Control.Monad as Exports hiding (fail, mapM_, sequence_, forM_, msum, mapM, sequence, forM)+import Control.Monad.IO.Class as Exports+import Control.Monad.Fail as Exports+import Control.Monad.Fix as Exports hiding (fix)+import Control.Monad.ST as Exports+import Data.Bits as Exports+import Data.Bool as Exports+import Data.Char as Exports+import Data.Coerce as Exports+import Data.Complex as Exports+import Data.Data as Exports+import Data.Dynamic as Exports+import Data.Either as Exports+import Data.Fixed as Exports+import Data.Foldable as Exports hiding (toList)+import Data.Function as Exports hiding (id, (.))+import Data.Functor as Exports+import Data.Functor.Identity as Exports+import Data.Int as Exports+import Data.IORef as Exports+import Data.Ix as Exports+import Data.List as Exports hiding (sortOn, isSubsequenceOf, uncons, concat, foldr, foldl1, maximum, minimum, product, sum, all, and, any, concatMap, elem, foldl, foldr1, notElem, or, find, maximumBy, minimumBy, mapAccumL, mapAccumR, foldl')+import Data.Maybe as Exports+import Data.Monoid as Exports hiding (Last(..), First(..), (<>))+import Data.Ord as Exports+import Data.Proxy as Exports+import Data.Ratio as Exports+import Data.Semigroup as Exports+import Data.STRef as Exports+import Data.String as Exports+import Data.Traversable as Exports+import Data.Tuple as Exports+import Data.Unique as Exports+import Data.Version as Exports+import Data.Word as Exports+import Debug.Trace as Exports+import Foreign.ForeignPtr as Exports+import Foreign.Ptr as Exports+import Foreign.StablePtr as Exports+import Foreign.Storable as Exports hiding (sizeOf, alignment)+import GHC.Conc as Exports hiding (withMVar, threadWaitWriteSTM, threadWaitWrite, threadWaitReadSTM, threadWaitRead)+import GHC.Exts as Exports (lazy, inline, sortWith, groupWith, IsList(..))+import GHC.Generics as Exports (Generic, Generic1)+import GHC.IO.Exception as Exports+import Numeric as Exports+import Prelude as Exports hiding (fail, concat, foldr, mapM_, sequence_, foldl1, maximum, minimum, product, sum, all, and, any, concatMap, elem, foldl, foldr1, notElem, or, mapM, sequence, id, (.))+import System.Environment as Exports+import System.Exit as Exports+import System.IO as Exports+import System.IO.Error as Exports+import System.IO.Unsafe as Exports+import System.Mem as Exports+import System.Mem.StableName as Exports+import System.Timeout as Exports+import Text.ParserCombinators.ReadP as Exports (ReadP, ReadS, readP_to_S, readS_to_P)+import Text.ParserCombinators.ReadPrec as Exports (ReadPrec, readPrec_to_P, readP_to_Prec, readPrec_to_S, readS_to_Prec)+import Text.Printf as Exports (printf, hPrintf)+import Text.Read as Exports (Read(..), readMaybe, readEither)+import Unsafe.Coerce as Exports++-- mtl+-------------------------+import Control.Monad.State.Strict as Exports hiding (fail)+
+ library/Deque/Strict.hs view
@@ -0,0 +1,230 @@+{-|+Definitions of strict Deque.++The typical `toList` and `fromList` conversions are provided by means of+the `Foldable` and `IsList` instances.+-}+module Deque.Strict+(+  Deque,+  fromConsAndSnocLists,+  cons,+  snoc,+  reverse,+  shiftLeft,+  shiftRight,+  filter,+  takeWhile,+  dropWhile,+  uncons,+  unsnoc,+  null,+  head,+  last,+  tail,+  init,+)+where++import Control.Monad (fail)+import Deque.Prelude hiding (tail, init, last, head, null, dropWhile, takeWhile, reverse, filter)+import qualified Deque.StrictList as StrictList++-- |+-- Strict double-ended queue (aka Dequeue or Deque) based on head-tail linked list.+data Deque a = Deque {-# UNPACK #-} !(StrictList.List a) {-# UNPACK #-} !(StrictList.List a)++-- |+-- /O(1)/.+-- Construct from cons and snoc lists.+fromConsAndSnocLists :: [a] -> [a] -> Deque a+fromConsAndSnocLists consList snocList = Deque (fromList snocList) (fromList consList)++-- |+-- /O(1)/.+-- Add element in the beginning.+cons :: a -> Deque a -> Deque a+cons a (Deque snocList consList) = Deque snocList (StrictList.Cons a consList)++-- |+-- /O(1)/.+-- Add element in the ending.+snoc :: a -> Deque a -> Deque a+snoc a (Deque snocList consList) = Deque (StrictList.Cons a snocList) consList++-- |+-- /O(1)/.+-- Revert the deque.+reverse :: Deque a -> Deque a+reverse (Deque snocList consList) = Deque consList snocList++-- |+-- /O(1)/, occasionally /O(n)/.+-- Move the first element to the end.+--+-- @+-- λ toList . shiftLeft $ fromList [1,2,3]+-- [2,3,1]+-- @+shiftLeft :: Deque a -> Deque a+shiftLeft deque = maybe deque (uncurry snoc) (uncons deque)++-- |+-- /O(1)/, occasionally /O(n)/.+-- Move the last element to the beginning.+--+-- @+-- λ toList . shiftRight $ fromList [1,2,3]+-- [3,1,2]+-- @+shiftRight :: Deque a -> Deque a+shiftRight deque = maybe deque (uncurry cons) (unsnoc deque)++-- |+-- /O(n)/.+-- Leave only the elements satisfying the predicate.+filter :: (a -> Bool) -> Deque a -> Deque a+filter predicate (Deque snocList consList) = let+  newConsList = StrictList.prependReversed+    (StrictList.filterReverse predicate consList)+    (StrictList.filterReverse predicate snocList)+  in Deque StrictList.Nil newConsList++-- |+-- /O(n)/.+-- Leave only the first elements satisfying the predicate.+takeWhile :: (a -> Bool) -> Deque a -> Deque a+takeWhile predicate (Deque snocList consList) = let+  newConsList = foldr+    (\ a nextState -> if predicate a+      then StrictList.Cons a nextState+      else StrictList.Nil)+    (StrictList.takeWhileFromEnding predicate snocList)+    consList+  in Deque StrictList.Nil newConsList++-- |+-- /O(n)/.+-- Drop the first elements satisfying the predicate.+dropWhile :: (a -> Bool) -> Deque a -> Deque a+dropWhile predicate (Deque snocList consList) = let+  newConsList = StrictList.dropWhile predicate consList+  in case newConsList of+    StrictList.Nil -> Deque StrictList.Nil (StrictList.dropWhileFromEnding predicate snocList)+    _ -> Deque snocList newConsList++-- |+-- /O(1)/, occasionally /O(n)/.+-- Get the first element and deque without it if it's not empty.+uncons :: Deque a -> Maybe (a, Deque a)+uncons (Deque snocList consList) = case consList of+  StrictList.Cons head tail -> Just (head, Deque snocList tail)+  _ -> case StrictList.reverse snocList of+    StrictList.Cons head tail -> Just (head, Deque StrictList.Nil tail)+    _ -> Nothing++-- |+-- /O(1)/, occasionally /O(n)/.+-- Get the last element and deque without it if it's not empty.+unsnoc :: Deque a -> Maybe (a, Deque a)+unsnoc (Deque snocList consList) = case snocList of+  StrictList.Cons head tail -> Just (head, Deque tail consList)+  _ -> case StrictList.reverse consList of+    StrictList.Cons head tail -> Just (head, Deque tail StrictList.Nil)+    _ -> Nothing++-- |+-- /O(1)/. +-- Check whether deque is empty.+null :: Deque a -> Bool+null = \ case+  Deque StrictList.Nil StrictList.Nil -> True+  _ -> False++-- |+-- /O(1)/, occasionally /O(n)/.+-- Get the first element if deque is not empty.+head :: Deque a -> Maybe a+head (Deque snocList consList) = case consList of+  StrictList.Cons head _ -> Just head+  _ -> StrictList.last snocList++-- |+-- /O(1)/, occasionally /O(n)/.+-- Get the last element if deque is not empty.+last :: Deque a -> Maybe a+last (Deque snocList consList) = case snocList of+  StrictList.Cons head _ -> Just head+  _ -> StrictList.last consList++-- |+-- /O(1)/, occasionally /O(n)/.+-- Keep all elements but the first one.+-- +-- In case of empty deque returns an empty deque.+tail :: Deque a -> Deque a+tail (Deque snocList consList) = case consList of+  StrictList.Nil -> Deque StrictList.Nil (StrictList.reverseInit snocList)+  _ -> Deque snocList (StrictList.tail consList)++-- |+-- /O(1)/, occasionally /O(n)/.+-- Keep all elements but the last one.+-- +-- In case of empty deque returns an empty deque.+init :: Deque a -> Deque a+init (Deque snocList consList) = case snocList of+  StrictList.Nil -> Deque (StrictList.reverseInit consList) StrictList.Nil+  _ -> Deque (StrictList.tail snocList) consList+++instance Eq a => Eq (Deque a) where+  (==) a b = toList a == toList b++instance Show a => Show (Deque a) where+  show = showString "fromList " . show . toList++instance IsList (Deque a) where+  type Item (Deque a) = a+  fromList list = Deque (StrictList.fromReverseList list) StrictList.Nil+  toList (Deque snocList consList) = foldr (:) (StrictList.toReverseList snocList) consList++instance Semigroup (Deque a) where+  (<>) (Deque snocList1 consList1) (Deque snocList2 consList2) = let+    snocList3 = snocList2+    consList3 = consList1 <> StrictList.prependReversed snocList1 consList2+    in Deque snocList3 consList3++instance Monoid (Deque a) where+  mempty = Deque StrictList.Nil StrictList.Nil+  mappend = (<>)++deriving instance Functor Deque++instance Foldable Deque where+  foldr step init (Deque snocList consList) = foldr step (foldr step init consList) (StrictList.reverse snocList)+  foldl' step init (Deque snocList consList) = foldl' step (foldl' step init consList) (StrictList.reverse consList)++instance Traversable Deque where+  traverse f (Deque ss cs) =+    (\cs' ss' -> Deque (StrictList.reverse ss') cs') <$> traverse f cs <*> traverse f (StrictList.reverse ss)++instance Applicative Deque where+  pure a = Deque StrictList.Nil (pure a)+  fs <*> as = fromList (toList fs <*> toList as)++instance Monad Deque where+  return = pure+  m >>= f = fromList (toList m >>= toList . f)+  fail = const mempty++instance Alternative Deque where+  empty = mempty+  (<|>) = mappend++instance MonadPlus Deque where+  mzero = empty+  mplus = (<|>)++instance MonadFail Deque where+  fail = const mempty
+ library/Deque/Strict/State.hs view
@@ -0,0 +1,115 @@+{-|+Strict Deque API lifted to a State monad, \"mtl\"-style.+-}+module Deque.Strict.State+where++import Deque.Prelude hiding (tail, init, last, head, null, dropWhile, takeWhile, reverse)+import Deque.Strict (Deque)+import qualified Deque.Strict as Deque+import qualified Deque.Prelude as Prelude+++-- |+-- /O(1)/.+-- Add element in the beginning.+cons :: MonadState (Deque a) m => a -> m ()+cons a = modify (Deque.cons a)++-- |+-- /O(1)/.+-- Add element in the ending.+snoc :: MonadState (Deque a) m => a -> m ()+snoc a = modify (Deque.snoc a)++-- |+-- /O(1)/.+-- Revert the deque.+reverse :: MonadState (Deque a) m => m ()+reverse = modify Deque.reverse++-- |+-- /O(1)/, occasionally /O(n)/.+-- Move the first element to the end.+shiftLeft :: MonadState (Deque a) m => m ()+shiftLeft = modify Deque.shiftLeft++-- |+-- /O(1)/, occasionally /O(n)/.+-- Move the last element to the beginning.+shiftRight :: MonadState (Deque a) m => m ()+shiftRight = modify Deque.shiftRight++-- |+-- /O(n)/.+-- Leave only the elements satisfying the predicate.+filter :: MonadState (Deque a) m => (a -> Bool) -> m ()+filter predicate = modify (Deque.filter predicate)++-- |+-- /O(n)/.+-- Leave only the first elements satisfying the predicate.+takeWhile :: MonadState (Deque a) m => (a -> Bool) -> m ()+takeWhile predicate = modify (Deque.takeWhile predicate)++-- |+-- /O(n)/.+-- Drop the first elements satisfying the predicate.+dropWhile :: MonadState (Deque a) m => (a -> Bool) -> m ()+dropWhile predicate = modify (Deque.dropWhile predicate)++-- |+-- /O(1)/, occasionally /O(n)/.+-- Get the first element and deque without it if it's not empty.+uncons :: MonadState (Deque a) m => m (Maybe a)+uncons = state (\ deque -> case Deque.uncons deque of+  Nothing -> (Nothing, deque)+  Just (a, newDeque) -> (Just a, newDeque))++-- |+-- /O(1)/, occasionally /O(n)/.+-- Get the last element and deque without it if it's not empty.+unsnoc :: MonadState (Deque a) m => m (Maybe a)+unsnoc = state (\ deque -> case Deque.unsnoc deque of+  Nothing -> (Nothing, deque)+  Just (a, newDeque) -> (Just a, newDeque))++-- |+-- /O(1)/. +-- Check whether deque is empty.+null :: MonadState (Deque a) m => m Bool+null = gets Deque.null++-- |+-- /O(1)/. +-- Check whether deque is empty.+length :: MonadState (Deque a) m => m Int+length = gets Prelude.length++-- |+-- /O(1)/, occasionally /O(n)/.+-- Get the first element if deque is not empty.+head :: MonadState (Deque a) m => m (Maybe a)+head = gets Deque.head++-- |+-- /O(1)/, occasionally /O(n)/.+-- Get the last element if deque is not empty.+last :: MonadState (Deque a) m => m (Maybe a)+last = gets Deque.last++-- |+-- /O(1)/, occasionally /O(n)/.+-- Keep all elements but the first one.+-- +-- In case of empty deque returns an empty deque.+tail :: MonadState (Deque a) m => m (Deque a)+tail = gets Deque.tail++-- |+-- /O(1)/, occasionally /O(n)/.+-- Keep all elements but the last one.+-- +-- In case of empty deque returns an empty deque.+init :: MonadState (Deque a) m => m (Deque a)+init = gets Deque.init
+ library/Deque/StrictList.hs view
@@ -0,0 +1,155 @@+module Deque.StrictList where++import Deque.Prelude hiding (takeWhile, dropWhile, reverse)+++data List a = Cons !a !(List a) | Nil deriving+  (Eq, Ord, Show, Read, Foldable, Traversable, Generic, Generic1, Data, Typeable)++instance IsList (List a) where+  type Item (List a) = a+  fromList = reverse . fromReverseList+  toList = \ case+    Cons head tail -> head : toList tail+    _ -> []++instance Semigroup (List a) where+  (<>) a = prependReversed (reverse a)++instance Monoid (List a) where+  mempty = Nil+  mappend = (<>)++instance Functor List where+  fmap f = reverse . mapReverse f++instance Applicative List where+  pure a = Cons a Nil+  (<*>) fList aList = reverse (apReverse fList aList)++instance Alternative List where+  empty = mempty+  (<|>) = mappend++mapReverse :: (a -> b) -> List a -> List b+mapReverse f = let+  loop !newList = \ case+    Cons head tail -> loop (Cons (f head) newList) tail+    _ -> newList+  in loop Nil++apReverse :: List (a -> b) -> List a -> List b+apReverse = let+  loop bList = \ case+    Cons f fTail -> \ case+      Cons a aTail -> loop (Cons (f a) bList) fTail aTail+      _ -> bList+    _ -> const bList+  in loop Nil++filterReverse :: (a -> Bool) -> List a -> List a+filterReverse predicate = let+  loop !newList = \ case+    Cons head tail -> if predicate head+      then loop (Cons head newList) tail+      else loop newList tail+    Nil -> newList+  in loop Nil++filter :: (a -> Bool) -> List a -> List a+filter predicate = reverse . filterReverse predicate++takeWhile :: (a -> Bool) -> List a -> List a+takeWhile predicate = \ case+  Cons head tail -> if predicate head+    then Cons head (takeWhile predicate tail)+    else Nil+  Nil -> Nil++reverse :: List a -> List a+reverse = foldl' (\ newList a -> Cons a newList) Nil++dropWhile :: (a -> Bool) -> List a -> List a+dropWhile predicate = \ case+  Cons head tail -> if predicate head+    then dropWhile predicate tail+    else Cons head tail+  Nil -> Nil++{-|+Same as @(`takeWhile` predicate . `reverse`)@.+E.g., ++>>> takeWhileFromEnding (> 2) (fromList [1,4,2,3,4,5])+fromList [5,4,3]+-}+takeWhileFromEnding :: (a -> Bool) -> List a -> List a+takeWhileFromEnding predicate = foldl'+  (\ newList a -> if predicate a+    then Cons a newList+    else Nil)+  Nil++{-|+Same as @(`dropWhile` predicate . `reverse`)@.+E.g., ++>>> dropWhileFromEnding (> 2) (fromList [1,4,2,3,4,5])+fromList [2,4,1]+-}+dropWhileFromEnding :: (a -> Bool) -> List a -> List a+dropWhileFromEnding predicate = let+  loop confirmed unconfirmed = \ case+    Cons head tail -> if predicate head+      then loop confirmed (Cons head unconfirmed) tail+      else let+        !newConfirmed = Cons head unconfirmed+        in loop newConfirmed newConfirmed tail+    Nil -> confirmed+  in loop Nil Nil++prependReversed :: List a -> List a -> List a+prependReversed = \ case+  Cons head tail -> prependReversed tail . Cons head+  Nil -> id++head :: List a -> Maybe a+head = \ case+  Cons head _ -> Just head+  _ -> Nothing++last :: List a -> Maybe a+last = let+  loop previous = \ case+    Cons head tail -> loop (Just head) tail+    _ -> previous+  in loop Nothing++tail :: List a -> List a+tail = \ case+  Cons head tail -> tail+  Nil -> Nil++reverseInit :: List a -> List a+reverseInit = let+  loop !confirmed unconfirmed = \ case+    Cons head tail -> loop unconfirmed (Cons head unconfirmed) tail+    _ -> confirmed+  in loop Nil Nil++init :: List a -> List a+init = reverse . reverseInit++fromReverseList :: [a] -> List a+fromReverseList = let+  loop !acc = \ case+    head : tail -> loop (Cons head acc) tail+    _ -> acc+  in loop Nil++toReverseList :: List a -> [a]+toReverseList = let+  loop !list = \ case+    Cons head tail -> loop (head : list) tail+    _ -> list+  in loop []
test/Main.hs view
@@ -1,6 +1,7 @@ module Main where -import Prelude+import Prelude hiding (toList)+import GHC.Exts as Exports (IsList(..)) import Test.QuickCheck.Instances import Test.Tasty import Test.Tasty.Runners@@ -8,27 +9,124 @@ import Test.Tasty.QuickCheck import qualified Test.QuickCheck as QuickCheck import qualified Test.QuickCheck.Property as QuickCheck-import qualified Deque as Deque import qualified Data.List as List+import qualified Deque.Lazy as Lazy+import qualified Deque.Strict as Strict   main =   defaultMain $-  testGroup "List roundtrips" $ let-  testPredicateProperty name listOp dequeOp =-    testProperty name $ \ (list1 :: [Int], list2 :: [Int], threshold :: Int, direction :: Int) -> let-      compare = case mod direction 5 of-        0 -> (>)-        1 -> (>=)-        2 -> (==)-        3 -> (<=)-        4 -> (<)-      predicate = compare threshold-      in-        listOp predicate (list1 <> list2) ===-        toList (dequeOp predicate (Deque.Deque (reverse list2) list1))-    in [-        testPredicateProperty "takeWhile" List.takeWhile Deque.takeWhile-        ,-        testPredicateProperty "dropWhile" List.dropWhile Deque.dropWhile-      ]+  testGroup "" $+  [+    testImplementation "Strict"+      toList fromList Strict.fromConsAndSnocLists+      Strict.cons Strict.snoc Strict.reverse+      Strict.shiftLeft Strict.shiftRight Strict.filter Strict.takeWhile Strict.dropWhile+      Strict.uncons Strict.unsnoc Strict.null Strict.head Strict.last Strict.tail Strict.init+    ,+    testImplementation "Lazy"+      toList fromList Lazy.fromConsAndSnocLists+      Lazy.cons Lazy.snoc Lazy.reverse+      Lazy.shiftLeft Lazy.shiftRight Lazy.filter Lazy.takeWhile Lazy.dropWhile+      Lazy.uncons Lazy.unsnoc Lazy.null Lazy.head Lazy.last Lazy.tail Lazy.init+  ]++{-|+Test group, which abstracts over the implementation of deque.+-}+testImplementation name+  (toList :: forall a. f a -> [a]) fromList fromConsAndSnocLists+  cons snoc reverse+  shiftLeft shiftRight filter takeWhile dropWhile+  uncons unsnoc null head last tail init =+    testGroup ("Deque implementation: " <> name) $+    [+      testProperty "toList" $ forAll dequeAndListGen $ \ (deque, list) ->+      toList deque === list+      ,+      testProperty "fromList" $ forAll listGen $ \ list ->+      toList (fromList list) === list+      ,+      testProperty "eq" $ forAll dequeAndListGen $ \ (deque, list) ->+      deque === fromList list+      ,+      testProperty "show" $ forAll dequeAndListGen $ \ (deque, list) ->+      show deque === "fromList " <> show list+      ,+      testProperty "cons" $ forAll ((,) <$> arbitrary <*> dequeAndListGen) $ \ (a, (deque, list)) ->+      toList (cons a deque) === a : list+      ,+      testProperty "snoc" $ forAll ((,) <$> arbitrary <*> dequeAndListGen) $ \ (a, (deque, list)) ->+      toList (snoc a deque) === list <> [a]+      ,+      testProperty "reverse" $ forAll dequeAndListGen $ \ (deque, list) ->+      toList (reverse deque) === List.reverse list+      ,+      testProperty "shiftLeft" $ forAll dequeAndListGen $ \ (deque, list) ->+      toList (shiftLeft deque) === List.drop 1 list <> List.take 1 list+      ,+      testProperty "shiftRight" $ forAll dequeAndListGen $ \ (deque, list) ->+      toList (shiftRight deque) === case list of+        [] -> []+        _ -> List.last list : List.init list+      ,+      testProperty "filter" $ forAll ((,) <$> predicateGen <*> dequeAndListGen) $ \ (predicate, (deque, list)) ->+      toList (filter predicate deque) === List.filter predicate list+      ,+      testProperty "takeWhile" $ forAll ((,) <$> predicateGen <*> dequeAndListGen) $ \ (predicate, (deque, list)) ->+      toList (takeWhile predicate deque) === List.takeWhile predicate list+      ,+      testProperty "dropWhile" $ forAll ((,) <$> predicateGen <*> dequeAndListGen) $ \ (predicate, (deque, list)) ->+      toList (dropWhile predicate deque) === List.dropWhile predicate list+      ,+      testProperty "uncons" $ forAll dequeAndListGen $ \ (deque, list) ->+      fmap (fmap toList) (uncons deque) === List.uncons list+      ,+      testProperty "unsnoc" $ forAll dequeAndListGen $ \ (deque, list) ->+      fmap (fmap toList) (unsnoc deque) === case list of+        [] -> Nothing+        _ -> Just (List.last list, List.init list)+      ,+      testProperty "null" $ forAll dequeAndListGen $ \ (deque, list) ->+      null deque === List.null list+      ,+      testProperty "head" $ forAll dequeAndListGen $ \ (deque, list) ->+      head deque === case list of+        head : _ -> Just head+        _ -> Nothing+      ,+      testProperty "last" $ forAll dequeAndListGen $ \ (deque, list) ->+      last deque === case list of+        [] -> Nothing+        _ -> Just (List.last list)+      ,+      testProperty "tail" $ forAll dequeAndListGen $ \ (deque, list) ->+      toList (tail deque) === case list of+        _ : tail -> tail+        _ -> []+      ,+      testProperty "init" $ forAll dequeAndListGen $ \ (deque, list) ->+      toList (init deque) === case list of+        [] -> []+        _ -> List.init list+      ,+      testProperty "ap" $ forAll ((,) <$> dequeAndListGen <*> dequeAndListGen) $ \ ((deque1, list1), (deque2, list2)) ->+      toList ((,) <$> deque1 <*> deque2) === ((,) <$> list1 <*> list2)+    ]+    where+      listGen = arbitrary @[Word8]+      dequeAndListGen = do+        consList <- listGen+        snocList <- listGen+        return (fromConsAndSnocLists consList snocList, consList <> List.reverse snocList)+      predicateGen = do+        op <- elements [(>), (>=), (==), (<=), (<)]+        x <- arbitrary @Word8+        return (op x)++{-|+A workaround to satisfy QuickCheck's requirements,+when we need to generate a predicate.+-}+instance Show (Word8 -> Bool) where+  show _ = "(Word8 -> Bool) function"