1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
|
{-# LANGUAGE CPP #-}
-- |
-- Definitions of lazy Deque.
--
-- The typical `toList` and `fromList` conversions are provided by means of
-- the `Foldable` and `IsList` instances.
module Deque.Lazy.Defs where
import qualified Data.List as List
import Deque.Prelude hiding (dropWhile, filter, head, init, last, null, reverse, tail, take, takeWhile)
-- |
-- Lazy double-ended queue (aka Dequeue or Deque) based on head-tail linked list.
data Deque a = Deque ![a] ![a]
-- |
-- \(\mathcal{O}(1)\).
-- Construct from cons and snoc lists.
fromConsAndSnocLists :: [a] -> [a] -> Deque a
fromConsAndSnocLists consList snocList = Deque consList snocList
-- |
-- \(\mathcal{O}(n)\).
-- Leave only the elements satisfying the predicate.
filter :: (a -> Bool) -> Deque a -> Deque a
filter predicate (Deque consList snocList) = Deque (List.filter predicate consList) (List.filter predicate snocList)
-- |
-- \(\mathcal{O}(n)\).
-- Leave only the specified amount of first elements.
take :: Int -> Deque a -> Deque a
take amount (Deque consList snocList) =
let newConsList =
let buildFromConsList amount =
if amount > 0
then \case
head : tail -> head : buildFromConsList (pred amount) tail
_ -> buildFromSnocList amount (List.reverse snocList)
else const []
buildFromSnocList amount =
if amount > 0
then \case
head : tail -> head : buildFromSnocList (pred amount) tail
_ -> []
else const []
in buildFromConsList amount consList
in Deque newConsList []
-- |
-- \(\mathcal{O}(n)\).
-- Drop the specified amount of first elements.
drop :: Int -> Deque a -> Deque a
drop amount (Deque consList snocList) =
let buildFromConsList amount =
if amount > 0
then \case
_ : tail -> buildFromConsList (pred amount) tail
_ -> buildFromSnocList amount (List.reverse snocList)
else \tail -> Deque tail snocList
buildFromSnocList amount =
if amount > 0
then \case
_ : tail -> buildFromSnocList (pred amount) tail
_ -> Deque [] []
else \tail -> Deque tail []
in buildFromConsList amount consList
-- |
-- \(\mathcal{O}(n)\).
-- Leave only the first elements satisfying the predicate.
takeWhile :: (a -> Bool) -> Deque a -> Deque a
takeWhile predicate (Deque consList snocList) =
let newConsList =
List.foldr
( \a nextState ->
if predicate a
then a : nextState
else []
)
(List.takeWhile predicate (List.reverse snocList))
consList
in Deque newConsList []
-- |
-- \(\mathcal{O}(n)\).
-- Drop the first elements satisfying the predicate.
dropWhile :: (a -> Bool) -> Deque a -> Deque a
dropWhile predicate (Deque consList snocList) =
let newConsList = List.dropWhile predicate consList
in case newConsList of
[] -> Deque (List.dropWhile predicate (List.reverse snocList)) []
_ -> Deque newConsList snocList
-- |
-- \(\mathcal{O}(n)\).
-- Perform `takeWhile` and `dropWhile` in a single operation.
span :: (a -> Bool) -> Deque a -> (Deque a, Deque a)
span predicate (Deque consList snocList) = case List.span predicate consList of
(consPrefix, consSuffix) ->
if List.null consSuffix
then case List.span predicate (List.reverse snocList) of
(snocPrefix, snocSuffix) ->
let prefix = Deque (consPrefix <> snocPrefix) []
suffix = Deque snocSuffix []
in (prefix, suffix)
else
let prefix = Deque consPrefix []
suffix = Deque consSuffix snocList
in (prefix, suffix)
-- |
-- \(\mathcal{O}(1)\), occasionally \(\mathcal{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)
-- |
-- \(\mathcal{O}(1)\), occasionally \(\mathcal{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)
-- |
-- \(\mathcal{O}(1)\).
-- Add element in the beginning.
cons :: a -> Deque a -> Deque a
cons a (Deque consList snocList) = Deque (a : consList) snocList
-- |
-- \(\mathcal{O}(1)\).
-- Add element in the ending.
snoc :: a -> Deque a -> Deque a
snoc a (Deque consList snocList) = Deque consList (a : snocList)
-- |
-- \(\mathcal{O}(1)\), occasionally \(\mathcal{O}(n)\).
-- Get the first element and deque without it if it's not empty.
uncons :: Deque a -> Maybe (a, Deque a)
uncons (Deque consList snocList) = case consList of
head : tail -> Just (head, Deque tail snocList)
_ -> case List.reverse snocList of
head : tail -> Just (head, Deque tail [])
_ -> Nothing
-- |
-- \(\mathcal{O}(1)\), occasionally \(\mathcal{O}(n)\).
-- Get the last element and deque without it if it's not empty.
unsnoc :: Deque a -> Maybe (a, Deque a)
unsnoc (Deque consList snocList) = case snocList of
head : tail -> Just (head, Deque consList tail)
_ -> case List.reverse consList of
head : tail -> Just (head, Deque [] tail)
_ -> Nothing
-- |
-- \(\mathcal{O}(n)\).
prepend :: Deque a -> Deque a -> Deque a
prepend (Deque consList1 snocList1) (Deque consList2 snocList2) =
let consList = consList1
snocList = snocList2 ++ foldl' (flip (:)) snocList1 consList2
in Deque consList snocList
-- |
-- \(\mathcal{O}(1)\).
-- Reverse the deque.
reverse :: Deque a -> Deque a
reverse (Deque consList snocList) = Deque snocList consList
-- |
-- \(\mathcal{O}(1)\).
-- Check whether deque is empty.
null :: Deque a -> Bool
null (Deque consList snocList) = List.null snocList && List.null consList
-- |
-- \(\mathcal{O}(1)\), occasionally \(\mathcal{O}(n)\).
-- Get the first element if deque is not empty.
head :: Deque a -> Maybe a
head = fmap fst . uncons
-- |
-- \(\mathcal{O}(1)\), occasionally \(\mathcal{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
-- |
-- \(\mathcal{O}(1)\), occasionally \(\mathcal{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
-- |
-- \(\mathcal{O}(1)\), occasionally \(\mathcal{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 = show . toList
instance Semigroup (Deque a) where
(<>) = prepend
instance Monoid (Deque a) where
mempty =
Deque [] []
mappend =
(<>)
instance Foldable Deque where
foldr step init (Deque consList snocList) = foldr step (foldl' (flip step) init snocList) consList
foldl' step init (Deque consList snocList) = foldr' (flip step) (foldl' step init consList) snocList
instance Traversable Deque where
traverse f (Deque cs ss) =
(\cs' ss' -> Deque cs' (List.reverse ss')) <$> traverse f cs <*> traverse f (List.reverse ss)
deriving instance Functor Deque
instance Applicative Deque where
pure a = Deque [] [a]
(<*>) (Deque fnConsList fnSnocList) (Deque argConsList argSnocList) =
let consList =
let fnStep fn resultConsList =
let argStep arg = (:) (fn arg)
in foldr argStep (foldr argStep resultConsList (List.reverse argSnocList)) argConsList
in foldr fnStep (foldr fnStep [] (List.reverse fnSnocList)) fnConsList
in Deque consList []
instance Monad Deque where
return = pure
(>>=) (Deque aConsList aSnocList) k =
let consList =
let aStep a accBConsList = case k a of
Deque bConsList bSnocList -> bConsList <> foldl' (flip (:)) accBConsList bSnocList
in foldr aStep (foldr aStep [] (List.reverse aSnocList)) aConsList
in Deque consList []
#if !(MIN_VERSION_base(4,13,0))
fail = const mempty
#endif
instance Alternative Deque where
empty = mempty
(<|>) = mappend
instance MonadPlus Deque where
mzero = empty
mplus = (<|>)
instance MonadFail Deque where
fail = const mempty
-- |
-- \(\mathcal{O}(1)\).
instance IsList (Deque a) where
type Item (Deque a) = a
fromList = flip Deque []
toList (Deque consList snocList) = consList <> List.reverse snocList
deriving instance Generic (Deque a)
deriving instance Generic1 Deque
instance (Hashable a) => Hashable (Deque a)
instance (NFData a) => NFData (Deque a)
instance NFData1 Deque
|