Idris2/libs/contrib/Data/Seq/Unsized.idr
2023-10-01 07:16:20 +01:00

225 lines
5.7 KiB
Idris

||| General purpose two-end finite sequences.
|||
||| This is implemented by finger tree.
module Data.Seq.Unsized
import Control.WellFounded
import public Data.Zippable
import Data.Seq.Internal
%default total
||| A two-end finite sequences.
export
data Seq : Type -> Type where
MkSeq : FingerTree (Elem e) -> Seq e
||| O(1). The empty sequence.
export
empty : Seq e
empty = MkSeq Empty
||| O(1). A singleton sequence.
export
singleton : e -> Seq e
singleton a = MkSeq (Single (MkElem a))
||| O(n). A sequence of length n with a the value of every element.
export
replicate : (n : Nat) -> (a : e) -> Seq e
replicate n a = MkSeq (replicate' n a)
||| O(1). The number of elements in the sequence.
export
length : Seq a -> Nat
length (MkSeq tr) = length' tr
||| O(n). Reverse the sequence.
export
reverse : Seq a -> Seq a
reverse (MkSeq tr) = MkSeq (reverseTree id tr)
infixr 5 `cons`
||| O(1). Add an element to the left end of a sequence.
export
cons : e -> Seq e -> Seq e
a `cons` MkSeq tr = MkSeq (MkElem a `consTree` tr)
infixl 5 `snoc`
||| O(1). Add an element to the right end of a sequence.
export
snoc : Seq e -> e -> Seq e
MkSeq tr `snoc` a = MkSeq (tr `snocTree` MkElem a)
||| O(log(min(m, n))). Concatenate two sequences.
export
(++) : Seq e -> Seq e -> Seq e
MkSeq t1 ++ MkSeq t2 = MkSeq (addTree0 t1 t2)
||| O(1). View from the left of the sequence.
export
viewl : Seq a -> Maybe (a, Seq a)
viewl (MkSeq tr) = case viewLTree tr of
Just (MkElem a, tr') => Just (a, MkSeq tr')
Nothing => Nothing
||| O(1). The first element of the sequence.
export
head : Seq a -> Maybe a
head s = fst <$> viewl s
||| O(1). The elements after the head of the sequence.
||| Returns an empty sequence when the sequence is empty.
export
tail : Seq a -> Seq a
tail s = case viewl s of
Just (_, s') => s'
Nothing => empty
||| O(1). View from the right of the sequence.
export
viewr : Seq a -> Maybe (Seq a, a)
viewr (MkSeq tr) = case viewRTree tr of
Just (tr', MkElem a) => Just (MkSeq tr', a)
Nothing => Nothing
||| O(1). The elements before the last element of the sequence.
||| Returns an empty sequence when the sequence is empty.
export
init : Seq a -> Seq a
init s = case viewr s of
Just (s', _) => s'
Nothing => empty
||| O(1). The last element of the sequence.
export
last : Seq a -> Maybe a
last s = snd <$> viewr s
||| O(n). Turn a list into a sequence.
export
fromList : List a -> Seq a
fromList xs = MkSeq (foldr (\x, t => MkElem x `consTree` t) Empty xs)
||| O(log(min(i, n-i))). The element at the specified position.
export
index : Nat -> Seq a -> Maybe a
index i (MkSeq t) = if i < length' t
then let (_, MkElem a) = lookupTree i t in Just a
else Nothing
||| O(log(min(i, n-i))). Update the element at the specified position.
||| If the position is out of range, the original sequence is returned.
export
adjust : (a -> a) -> Nat -> Seq a -> Seq a
adjust f i s@(MkSeq t) = if i < length' t
then MkSeq $ adjustTree (const (map f)) i t
else s
||| O(log(min(i, n-i))). Replace the element at the specified position.
||| If the position is out of range, the original sequence is returned.
export
update : Nat -> a -> Seq a -> Seq a
update i a t = adjust (const a) i t
||| O(log(min(i, n-i))). Split a sequence at a given position.
||| splitAt i s = (take i s, drop i s)
export
splitAt : Nat -> Seq a -> (Seq a, Seq a)
splitAt i s@(MkSeq t) = if i < length' t
then let (l, r) = split i t
in (MkSeq l, MkSeq r)
else (s, empty)
||| O(log(min(i,n-i))). The first i elements of a sequence.
||| If the sequence contains fewer than i elements, the whole sequence is returned.
export
take : Nat -> Seq a -> Seq a
take i seq = fst (splitAt i seq)
||| O(log(min(i,n-i))). Elements of a sequence after the first i.
||| If the sequence contains fewer than i elements, the empty sequence is returned.
export
drop : Nat -> Seq a -> Seq a
drop i seq = snd (splitAt i seq)
||| Dump the internal structure of the finger tree.
export
show' : Show a => Seq a -> String
show' (MkSeq tr) = showPrec Open tr
public export
implementation Eq a => Eq (Seq a) where
MkSeq x == MkSeq y = x == y
public export
implementation Ord a => Ord (Seq a) where
compare (MkSeq x) (MkSeq y) = compare x y
public export
implementation Functor Seq where
map f (MkSeq tr) = MkSeq (map (map f) tr)
public export
implementation Foldable Seq where
foldr f z (MkSeq tr) = foldr (f . unElem) z tr
foldl f z (MkSeq tr) = foldl (\acc, (MkElem elem) => f acc elem) z tr
toList (MkSeq tr) = toList' tr
null (MkSeq Empty) = True
null _ = False
public export
implementation Traversable Seq where
traverse f (MkSeq tr) = MkSeq <$> traverse (map MkElem . f . unElem) tr
public export
implementation Show a => Show (Seq a) where
showPrec p = showPrec p . toList
public export
implementation Zippable Seq where
zipWith f (MkSeq x) (MkSeq y) = MkSeq (zipWith' f x y)
zipWith3 f (MkSeq x) (MkSeq y) (MkSeq z) = MkSeq (zipWith3' f x y z)
unzipWith f (MkSeq zs) = let (xs, ys) = unzipWith' f zs in (MkSeq xs, MkSeq ys)
unzipWith3 f (MkSeq ws) = let (xs, ys, zs) = unzipWith3' f ws in (MkSeq xs, MkSeq ys, MkSeq zs)
public export
implementation Semigroup (Seq a) where
(<+>) = (++)
public export
implementation Monoid (Seq a) where
neutral = empty
||| This implementation is differnt from that of Seq.
public export
implementation Applicative Seq where
pure = singleton
fs <*> xs = foldMap (\f => map f xs) fs
public export
[ListLike] Alternative Seq where
empty = empty
a <|> b = a ++ b
public export
[MaybeLike] Alternative Seq where
empty = empty
MkSeq Empty <|> b = b
a <|> _ = a
public export
implementation Monad Seq where
xs >>= f = foldMap f xs
public export
implementation Sized (Seq a) where
size (MkSeq s) = size s