-- | -- Module : Data.Edison.Seq -- Copyright : Copyright (c) 1998-1999 Chris Okasaki -- License : MIT; see COPYRIGHT file for terms and conditions -- -- Maintainer : robdockins AT fastmail DOT fm -- Stability : stable -- Portability : GHC, Hugs (MPTC and FD) -- -- The sequence abstraction is usually viewed as a hierarchy of ADTs -- including lists, queues, deques, catenable lists, etc. However, such -- a hierarchy is based on efficiency rather than functionality. For example, -- a list supports all the operations that a deque supports, even though -- some of the operations may be inefficient. Hence, in Edison, all sequence -- data structures are defined as instances of the single Sequence class: -- -- @ class (Functor s, MonadPlus s) => Sequence s@ -- -- All sequences are also instances of 'Functor', 'Monad', and 'MonadPlus'. -- In addition, all sequences are expected to be instances of @Eq@, @Show@, -- and @Read@, although this is not enforced. -- -- We follow the naming convention that every module implementing sequences -- defines a type constructor named @Seq@. -- -- For each method the \"default\" complexity is listed. Individual -- implementations may differ for some methods. The documentation for -- each implementation will list those methods for which the running time -- differs from these. -- -- A description of each Sequence function appears below. In most cases -- psudeocode is also provided. Obviously, the psudeocode is illustrative only. -- -- Sequences are represented in psudecode between angle brackets: -- -- > -- -- Such that @x0@ is at the left (front) of the sequence and -- @xn-1@ is at the right (rear) of the sequence. module Data.Edison.Seq ( -- * Superclass aliases -- ** Functor aliases map -- ** Monad aliases , singleton , concatMap -- ** MonadPlus aliases , empty , append -- * The Sequence class , Sequence (..) ) where import Prelude hiding (concat,reverse,map,concatMap,foldr,foldl,foldr1,foldl1, filter,takeWhile,dropWhile,lookup,take,drop,splitAt, zip,zip3,zipWith,zipWith3,unzip,unzip3,null) import Control.Monad import Data.Monoid import Data.Edison.Prelude -- | Return the result of applying a function to -- every element of a sequence. Identical -- to @fmap@ from @Functor@. -- -- > map f = -- -- /Axioms:/ -- -- * @map f empty = empty@ -- -- * @map f (lcons x xs) = lcons (f x) (map f xs)@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( t * n )@ -- where @t@ is the running time of @f@ map :: Sequence s => (a -> b) -> s a -> s b map = fmap -- | Create a singleton sequence. Identical to @return@ -- from @Monad@. -- -- > singleton x = -- -- /Axioms:/ -- -- * @singleton x = lcons x empty = rcons x empty@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( 1 )@ singleton :: Sequence s => a -> s a singleton = return -- | Apply a sequence-producing function to every element -- of a sequence and flatten the result. 'concatMap' -- is the bind @(>>=)@ operation of from @Monad@ with the -- arguments in the reverse order. -- -- > concatMap f xs = concat (map f xs) -- -- /Axioms:/ -- -- * @concatMap f xs = concat (map f xs)@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( t * n + m )@ -- where @n@ is the length of the input sequence, @m@ is the -- length of the output sequence, and @t@ is the running time of @f@ concatMap :: Sequence s => (a -> s b) -> s a -> s b concatMap = flip (>>=) -- | The empty sequence. Identical to @mzero@ -- from @MonadPlus@. -- -- > empty = <> -- -- This function is always /unambiguous/. -- -- Default running time: @O( 1 )@ empty :: Sequence s => s a empty = mzero -- | Append two sequence, with the first argument on the left -- and the second argument on the right. Identical to @mplus@ -- from @MonadPlus@. -- -- > append = -- -- /Axioms:/ -- -- * @append xs ys = foldr lcons ys xs@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( n1 )@ append :: Sequence s => s a -> s a -> s a append = mplus -- | The 'Sequence' class defines an interface for datatypes which -- implement sequences. A description for each function is -- given below. class (Functor s, MonadPlus s) => Sequence s where -- | Add a new element to the front\/left of a sequence -- -- > lcons x = -- -- /Axioms:/ -- -- * @lcons x xs = append (singleton x) xs@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( 1 )@ lcons :: a -> s a -> s a -- | Add a new element to the right\/rear of a sequence -- -- > rcons x = -- -- /Axioms:/ -- -- * @rcons x xs = append xs (singleton x)@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( n )@ rcons :: a -> s a -> s a -- | Convert a list into a sequence -- -- > fromList [x0,...,xn-1] = -- -- /Axioms:/ -- -- * @fromList xs = foldr lcons empty xs@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( n )@ fromList :: [a] -> s a -- | Create a sequence containing @n@ copies of the given element. -- Return 'empty' if @n\<0@. -- -- @copy n x = \@ -- -- /Axioms:/ -- -- * @n > 0 ==> copy n x = cons x (copy (n-1) x)@ -- -- * @n \<= 0 ==> copy n x = empty@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( n )@ copy :: Int -> a -> s a -- | Separate a sequence into its first (leftmost) element and the -- remaining sequence. Calls 'fail' if the sequence is empty. -- -- /Axioms:/ -- -- * @lview empty = fail@ -- -- * @lview (lcons x xs) = return (x,xs)@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( 1 )@ lview :: (Monad m) => s a -> m (a, s a) -- | Return the first element of a sequence. -- Signals an error if the sequence is empty. -- -- /Axioms:/ -- -- * @lhead empty = undefined@ -- -- * @lhead (lcons x xs) = x@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( 1 )@ lhead :: s a -> a -- | Returns the first element of a sequence. -- Calls 'fail' if the sequence is empty. -- -- /Axioms:/ -- -- * @lheadM empty = fail@ -- -- * @lheadM (lcons x xs) = return x@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( 1 )@ lheadM :: (Monad m) => s a -> m a -- | Delete the first element of the sequence. -- Signals error if sequence is empty. -- -- /Axioms:/ -- -- * @ltail empty = undefined@ -- -- * @ltail (lcons x xs) = xs@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( 1 )@ ltail :: s a -> s a -- | Delete the first element of the sequence. -- Calls 'fail' if the sequence is empty. -- -- /Axioms:/ -- -- * @ltailM empty = fail@ -- -- * @ltailM (lcons x xs) = return xs@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( 1 )@ ltailM :: (Monad m) => s a -> m (s a) -- | Separate a sequence into its last (rightmost) element and the -- remaining sequence. Calls 'fail' if the sequence is empty. -- -- /Axioms:/ -- -- * @rview empty = fail@ -- -- * @rview (rcons x xs) = return (x,xs)@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( n )@ rview :: (Monad m) => s a -> m (a, s a) -- | Return the last (rightmost) element of the sequence. -- Signals error if sequence is empty. -- -- /Axioms:/ -- -- * @rhead empty = undefined@ -- -- * @rhead (rcons x xs) = x@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( n )@ rhead :: s a -> a -- | Returns the last element of the sequence. -- Calls 'fail' if the sequence is empty. -- -- /Axioms:/ -- -- * @rheadM empty = fail@ -- -- * @rheadM (rcons x xs) = return x@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( n )@ rheadM :: (Monad m) => s a -> m a -- | Delete the last (rightmost) element of the sequence. -- Signals an error if the sequence is empty. -- -- /Axioms:/ -- -- * @rtail empty = undefined@ -- -- * @rtail (rcons x xs) = xs@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( n )@ rtail :: s a -> s a -- | Delete the last (rightmost) element of the sequence. -- Calls 'fail' of the sequence is empty -- -- /Axioms:/ -- -- * @rtailM empty = fail@ -- -- * @rtailM (rcons x xs) = return xs@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( n )@ rtailM :: (Monad m) => s a -> m (s a) -- | Returns 'True' if the sequence is empty and 'False' otherwise. -- -- > null = (n==0) -- -- /Axioms:/ -- -- * @null xs = (size xs == 0)@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( 1 )@ null :: s a -> Bool -- | Returns the length of a sequence. -- -- > size = n -- -- /Axioms:/ -- -- * @size empty = 0@ -- -- * @size (lcons x xs) = 1 + size xs@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( n )@ size :: s a -> Int -- | Convert a sequence to a list. -- -- > toList = [x0,...,xn-1] -- -- /Axioms:/ -- -- * @toList empty = []@ -- -- * @toList (lcons x xs) = x : toList xs@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( n )@ toList :: s a -> [a] -- | Flatten a sequence of sequences into a simple sequence. -- -- > concat xss = foldr append empty xss -- -- /Axioms:/ -- -- * @concat xss = foldr append empty xss@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( n + m )@ -- where @n@ is the length of the input sequence and @m@ is -- length of the output sequence. concat :: s (s a) -> s a -- | Reverse the order of a sequence -- -- > reverse = -- -- /Axioms:/ -- -- * @reverse empty = empty@ -- -- * @reverse (lcons x xs) = rcons x (reverse xs)@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( n )@ reverse :: s a -> s a -- | Reverse a sequence onto the front of another sequence. -- -- > reverseOnto = -- -- /Axioms:/ -- -- * @reverseOnto xs ys = append (reverse xs) ys@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( n1 )@ reverseOnto :: s a -> s a -> s a -- | Combine all the elements of a sequence into a single value, -- given a combining function and an initial value. The order -- in which the elements are applied to the combining function -- is unspecified. @fold@ is one of the few ambiguous sequence -- functions. -- -- /Axioms:/ -- -- * @fold f c empty = c@ -- -- * @f is fold-commutative ==> fold f = foldr f = foldl f@ -- -- @fold f@ is /unambiguous/ iff @f@ is fold-commutative. -- -- Default running type: @O( t * n )@ -- where @t@ is the running tome of @f@. fold :: (a -> b -> b) -> b -> s a -> b -- | A strict variant of 'fold'. @fold'@ is one of the few ambiguous -- sequence functions. -- -- /Axioms:/ -- -- * @forall a. f a _|_ = _|_ ==> fold f x xs = fold' f x xs@ -- -- @fold f@ is /unambiguous/ iff @f@ is fold-commutative. -- -- Default running type: @O( t * n )@ -- where @t@ is the running tome of @f@. fold' :: (a -> b -> b) -> b -> s a -> b -- | Combine all the elements of a non-empty sequence into a -- single value, given a combining function. Signals an error -- if the sequence is empty. -- -- /Axioms:/ -- -- * @f is fold-commutative ==> fold1 f = foldr1 f = foldl1 f@ -- -- @fold1 f@ is /unambiguous/ iff @f@ is fold-commutative. -- -- Default running type: @O( t * n )@ -- where @t@ is the running tome of @f@. fold1 :: (a -> a -> a) -> s a -> a -- | A strict variant of 'fold1'. -- -- /Axioms:/ -- -- * @forall a. f a _|_ = _|_ ==> fold1' f xs = fold1 f xs@ -- -- @fold1' f@ is /unambiguous/ iff @f@ is fold-commutative. -- -- Default running time: @O( t * n )@ -- where @t@ is the running time of @f@ fold1' :: (a -> a -> a) -> s a -> a -- | Combine all the elements of a sequence into a single value, -- given a combining function and an initial value. The function -- is applied with right nesting. -- -- > foldr (%) c = x0 % (x1 % ( ... % (xn-1 % c))) -- -- /Axioms:/ -- -- * @foldr f c empty = c@ -- -- * @foldr f c (lcons x xs) = f x (foldr f c xs)@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( t * n )@ -- where @t@ is the running time of @f@ foldr :: (a -> b -> b) -> b -> s a -> b -- | Strict variant of 'foldr'. -- -- /Axioms:/ -- -- * @forall a. f a _|_ = _|_ ==> foldr f x xs = foldr' f x xs@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( t * n )@ -- where @t@ is the running time of @f@ foldr' :: (a -> b -> b) -> b -> s a -> b -- | Combine all the elements of a sequence into a single value, -- given a combining function and an initial value. The function -- is applied with left nesting. -- -- > foldl (%) c = (((c % x0) % x1) % ... ) % xn-1 -- -- /Axioms:/ -- -- * @foldl f c empty = c@ -- -- * @foldl f c (lcons x xs) = foldl f (f c x) xs@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( t * n )@ -- where @t@ is the running time of @f@ foldl :: (b -> a -> b) -> b -> s a -> b -- | Strict variant of 'foldl'. -- -- /Axioms:/ -- -- * forall a. f _|_ a = _|_ ==> foldl f z xs = foldl' f z xs -- -- This function is always /unambiguous/. -- -- Default running time: @O( t * n )@ -- where @t@ is the running time of @f@ foldl' :: (b -> a -> b) -> b -> s a -> b -- | Combine all the elements of a non-empty sequence into a -- single value, given a combining function. The function -- is applied with right nesting. Signals an error if the -- sequence is empty. -- -- > foldr1 (+) -- > | n==0 = error "ModuleName.foldr1: empty sequence" -- > | n>0 = x0 + (x1 + ... + xn-1) -- -- /Axioms:/ -- -- * @foldr1 f empty = undefined@ -- -- * @foldr1 f (rcons x xs) = foldr f x xs@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( t * n )@ -- where @t@ is the running time of @f@ foldr1 :: (a -> a -> a) -> s a -> a -- | Strict variant of 'foldr1'. -- -- /Axioms:/ -- -- * forall a. f a _|_ = _|_ ==> foldr1 f xs = foldr1' f xs -- -- This function is always /unambiguous/. -- -- Default running time: @O( t * n )@ -- where @t@ is the running time of @f@ foldr1' :: (a -> a -> a) -> s a -> a -- | Combine all the elements of a non-empty sequence into -- a single value, given a combining function. The function -- is applied with left nesting. Signals an error if the -- sequence is empty. -- -- > foldl1 (+) -- > | n==0 = error "ModuleName.foldl1: empty sequence" -- > | n>0 = (x0 + x1) + ... + xn-1 -- -- /Axioms:/ -- -- * @foldl1 f empty = undefined@ -- -- * @foldl1 f (lcons x xs) = foldl f x xs@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( t * n )@ -- where @t@ is the running time of @f@ foldl1 :: (a -> a -> a) -> s a -> a -- | Strict variant of 'foldl1'. -- -- /Axioms:/ -- -- * forall a. f _|_ a = _|_ ==> foldl1 f xs = foldl1' f xs -- -- This function is always /unambiguous/. -- -- Default running time: @O( t * n )@ -- where @t@ is the running time of @f@ foldl1' :: (a -> a -> a) -> s a -> a -- | See 'reduce1' for additional notes. -- -- > reducer f x xs = reduce1 f (cons x xs) -- -- /Axioms:/ -- -- * @reducer f c xs = foldr f c xs@ for associative @f@ -- -- @reducer f@ is unambiguous iff @f@ is an associative function. -- -- Default running time: @O( t * n )@ -- where @t@ is the running time of @f@ reducer :: (a -> a -> a) -> a -> s a -> a -- | Strict variant of 'reducer'. -- -- See 'reduce1' for additional notes. -- -- /Axioms:/ -- -- * @forall a. f a _|_ = _|_ && forall a. f _|_ a = _|_ ==> -- reducer f x xs = reducer' f x xs@ -- -- @reducer' f@ is unambiguous iff @f@ is an associative function. -- -- Default running time: @O( t * n )@ -- where @t@ is the running time of @f@ reducer' :: (a -> a -> a) -> a -> s a -> a -- | See 'reduce1' for additional notes. -- -- > reducel f x xs = reduce1 f (rcons x xs) -- -- /Axioms:/ -- -- * @reducel f c xs = foldl f c xs@ for associative @f@ -- -- @reducel f@ is unambiguous iff @f@ is an associative function. -- -- Default running time: @O( t * n )@ -- where @t@ is the running time of @f@ reducel :: (a -> a -> a) -> a -> s a -> a -- | Strict variant of 'reducel'. -- -- See 'reduce1' for additional notes. -- -- /Axioms:/ -- -- * @forall a. f a _|_ = _|_ && forall a. f _|_ a = _|_ ==> -- reducel f x xs = reducel' f x xs@ -- -- @reducel' f@ is unambiguous iff @f@ is an associative function. -- -- Default running time: @O( t * n )@ -- where @t@ is the running time of @f@ reducel' :: (a -> a -> a) -> a -> s a -> a -- | A reduce is similar to a fold, but combines elements in a balanced fashion. -- The combining function should usually be associative. If the combining -- function is associative, the various reduce functions yield the same -- results as the corresponding folds. -- -- What is meant by \"in a balanced fashion\"? We mean that -- @reduce1 (%) \@ equals some complete parenthesization of -- @x0 % x1 % ... % xn-1@ such that the nesting depth of parentheses -- is @O( log n )@. The precise shape of this parenthesization is -- unspecified. -- -- > reduce1 f = x -- > reduce1 f = -- > f (reduce1 f ) (reduce1 f ) -- -- for some @i@ such that @ 0 \<= i && i \< n-1 @ -- -- Although the exact value of i is unspecified it tends toward @n\/2@ -- so that the depth of calls to @f@ is at most logarithmic. -- -- Note that @reduce@* are some of the only sequence operations for which -- different implementations are permitted to yield different answers. Also -- note that a single implementation may choose different parenthisizations -- for different sequences, even if they are the same length. This will -- typically happen when the sequences were constructed differently. -- -- The canonical applications of the reduce functions are algorithms like -- merge sort where: -- -- > mergesort xs = reducer merge empty (map singleton xs) -- -- -- /Axioms:/ -- -- * @reduce1 f empty = undefined@ -- -- * @reduce1 f xs = foldr1 f xs = foldl1 f xs@ for associative @f@ -- -- @reduce1 f@ is unambiguous iff @f@ is an associative function. -- -- Default running time: @O( t * n )@ -- where @t@ is the running time of @f@ reduce1 :: (a -> a -> a) -> s a -> a -- | Strict variant of 'reduce1'. -- -- /Axioms:/ -- -- * @forall a. f a _|_ = _|_ && forall a. f _|_ a = _|_ ==> -- reduce1 f xs = reduce1' f xs@ -- -- @reduce1' f@ is unambiguous iff @f@ is an associative function. -- -- Default running time: @O( t * n )@ -- where @t@ is the running time of @f@ reduce1' :: (a -> a -> a) -> s a -> a -- | Extract a prefix of length @i@ from the sequence. Return -- 'empty' if @i@ is negative, or the entire sequence if @i@ -- is too large. -- -- > take i xs = fst (splitAt i xs) -- -- /Axioms:/ -- -- * @i \< 0 ==> take i xs = empty@ -- -- * @i > size xs ==> take i xs = xs@ -- -- * @size xs == i ==> take i (append xs ys) = xs@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( i )@ take :: Int -> s a -> s a -- | Delete a prefix of length @i@ from a sequence. Return -- the entire sequence if @i@ is negative, or 'empty' if -- @i@ is too large. -- -- > drop i xs = snd (splitAt i xs) -- -- /Axioms:/ -- -- * @i \< 0 ==> drop i xs = xs@ -- -- * @i > size xs ==> drop i xs = empty@ -- -- * @size xs == i ==> drop i (append xs ys) = ys@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( i )@ drop :: Int -> s a -> s a -- | Split a sequence into a prefix of length @i@ -- and the remaining sequence. Behaves the same -- as the corresponding calls to 'take' and 'drop' -- if @i@ is negative or too large. -- -- > splitAt i xs -- > | i < 0 = (<> , ) -- > | i < n = (, ) -- > | i >= n = (, <> ) -- -- /Axioms:/ -- -- * @splitAt i xs = (take i xs,drop i xs)@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( i )@ splitAt :: Int -> s a -> (s a, s a) -- | Extract a subsequence from a sequence. The integer -- arguments are \"start index\" and \"length\" NOT -- \"start index\" and \"end index\". Behaves the same -- as the corresponding calls to 'take' and 'drop' if the -- start index or length are negative or too large. -- -- > subseq i len xs = take len (drop i xs) -- -- /Axioms:/ -- -- * @subseq i len xs = take len (drop i xs)@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( i + len )@ subseq :: Int -> Int -> s a -> s a -- | Extract the elements of a sequence that satisfy the -- given predicate, retaining the relative ordering of -- elements from the original sequence. -- -- > filter p xs = foldr pcons empty xs -- > where pcons x xs = if p x then cons x xs else xs -- -- /Axioms:/ -- -- * @filter p empty = empty@ -- -- * @filter p (lcons x xs) = if p x -- then lcons x (filter p xs) -- else filter p xs@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( t * n )@ -- where @t@ is the running time of @p@ filter :: (a -> Bool) -> s a -> s a -- | Separate the elements of a sequence into those that -- satisfy the given predicate and those that do not, -- retaining the relative ordering of elements from the -- original sequence. -- -- > partition p xs = (filter p xs, filter (not . p) xs) -- -- /Axioms:/ -- -- * @partition p xs = (filter p xs, filter (not . p) xs)@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( t * n )@ -- where @t@ is the running time of @p@ partition :: (a -> Bool) -> s a -> (s a, s a) -- | Extract the maximal prefix of elements satisfying the -- given predicate. -- -- > takeWhile p xs = fst (splitWhile p xs) -- -- /Axioms:/ -- -- * @takeWhile p empty = empty@ -- -- * @takeWhile p (lcons x xs) = if p x -- then lcons x (takeWhile p xs) -- else empty@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( t * n )@ -- where @t@ is the running time of @p@ takeWhile :: (a -> Bool) -> s a -> s a -- | Delete the maximal prefix of elements satisfying the -- given predicate. -- -- > dropWhile p xs = snd (splitWhile p xs) -- -- /Axioms:/ -- -- * @dropWhile p empty = empty@ -- -- * @dropWhile p (lcons x xs) = if p x -- then dropWhile p xs -- else lcons x xs@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( t * n )@ -- where @t@ is the running time of @p@ dropWhile :: (a -> Bool) -> s a -> s a -- | Split a sequence into the maximal prefix of elements -- satisfying the given predicate, and the remaining sequence. -- -- > splitWhile p = (, ) -- > where i = min j such that p xj (or n if no such j) -- -- /Axioms:/ -- -- * @splitWhile p xs = (takeWhile p xs,dropWhile p xs)@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( t * n )@ -- where @t@ is the running time of @p@ splitWhile :: (a -> Bool) -> s a -> (s a, s a) -- | Test whether an index is valid for the given sequence. All indexes -- are 0 based. -- -- > inBounds i = (0 <= i && i < n) -- -- /Axioms:/ -- -- * @inBounds i xs = (0 \<= i && i \< size xs)@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( i )@ inBounds :: Int -> s a -> Bool -- | Return the element at the given index. All indexes are 0 based. -- Signals error if the index out of bounds. -- -- > lookup i xs@ -- > | inBounds i xs = xi -- > | otherwise = error "ModuleName.lookup: index out of bounds" -- -- /Axioms:/ -- -- * @not (inBounds i xs) ==> lookup i xs = undefined@ -- -- * @size xs == i ==> lookup i (append xs (lcons x ys)) = x@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( i )@ lookup :: Int -> s a -> a -- | Return the element at the given index. All indexes are 0 based. -- Calls 'fail' if the index is out of bounds. -- -- > lookupM i xs@ -- > | inBounds i xs = Just xi -- > | otherwise = Nothing -- -- /Axioms:/ -- -- * @not (inBounds i xs) ==> lookupM i xs = fail@ -- -- * @size xs == i ==> lookupM i (append xs (lcons x ys)) = return x@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( i )@ lookupM :: (Monad m) => Int -> s a -> m a -- | Return the element at the given index, or the -- default argument if the index is out of bounds. All indexes are -- 0 based. -- -- > lookupWithDefault d i xs@ -- > | inBounds i xs = xi -- > | otherwise = d -- -- /Axioms:/ -- -- * @not (inBounds i xs) ==> lookupWithDefault d i xs = d@ -- -- * @size xs == i ==> lookupWithDefault d i (append xs (lcons x ys)) = x@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( i )@ lookupWithDefault :: a -> Int -> s a -> a -- | Replace the element at the given index, or return -- the original sequence if the index is out of bounds. -- All indexes are 0 based. -- -- > update i y xs@ -- > | inBounds i xs = -- > | otherwise = xs -- -- /Axioms:/ -- -- * @not (inBounds i xs) ==> update i y xs = xs@ -- -- * @size xs == i ==> update i y (append xs (lcons x ys)) = -- append xs (lcons y ys)@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( i )@ update :: Int -> a -> s a -> s a -- | Apply a function to the element at the given index, or -- return the original sequence if the index is out of bounds. -- All indexes are 0 based. -- -- > adjust f i xs@ -- > | inBounds i xs = -- > | otherwise = xs -- -- /Axioms:/ -- -- * @not (inBounds i xs) ==> adjust f i xs = xs@ -- -- * @size xs == i ==> adjust f i (append xs (lcons x ys)) = -- append xs (cons (f x) ys)@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( i + t )@ -- where @t@ is the running time of @f@ adjust :: (a -> a) -> Int -> s a -> s a -- map a single element -- | Like 'map', but include the index with each element. -- All indexes are 0 based. -- -- > mapWithIndex f = -- -- /Axioms:/ -- -- * @mapWithIndex f empty = empty@ -- -- * @mapWithIndex f (rcons x xs) = rcons (f (size xs) x) (mapWithIndex f xs)@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( t * n )@ -- where @t@ is the running time of @f@ mapWithIndex :: (Int -> a -> b) -> s a -> s b -- | Like 'foldr', but include the index with each element. -- All indexes are 0 based. -- -- > foldrWithIndex f c = -- > f 0 x0 (f 1 x1 (... (f (n-1) xn-1 c))) -- -- /Axioms:/ -- -- * @foldrWithIndex f c empty = c@ -- -- * @foldrWithIndex f c (rcons x xs) = -- foldrWithIndex f (f (size xs) x c) xs@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( t * n )@ -- where @t@ is the running time of @f@ foldrWithIndex :: (Int -> a -> b -> b) -> b -> s a -> b -- | Strict variant of 'foldrWithIndex'. -- -- /Axioms:/ -- -- * @forall i a. f i a _|_ = _|_ ==> foldrWithIndex f x xs = -- foldrWithIndex' f x xs@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( t * n )@ -- where @t@ is the running time of @f@ foldrWithIndex' :: (Int -> a -> b -> b) -> b -> s a -> b -- | Like 'foldl', but include the index with each element. -- All indexes are 0 based. -- -- > foldlWithIndex f c = -- > f (...(f (f c 0 x0) 1 x1)...) (n-1) xn-1) -- -- /Axioms:/ -- -- * @foldlWithIndex f c empty = c@ -- -- * @foldlWithIndex f c (rcons x xs) = -- f (foldlWithIndex f c xs) (size xs) x@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( t * n )@ -- where @t@ is the running time of @f@ foldlWithIndex :: (b -> Int -> a -> b) -> b -> s a -> b -- | Strict variant of 'foldlWithIndex'. -- -- /Axioms:/ -- -- * @forall i a. f _|_ i a = _|_ ==> foldlWithIndex f x xs = -- foldlWithIndex' f x xs@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( t * n )@ -- where @t@ is the running time of @f@ foldlWithIndex' :: (b -> Int -> a -> b) -> b -> s a -> b -- | Combine two sequences into a sequence of pairs. If the -- sequences are different lengths, the excess elements of the -- longer sequence is discarded. -- -- > zip = <(x0,y0),...,(xj-1,yj-1)> -- > where j = min {n,m} -- -- /Axioms:/ -- -- * @zip xs ys = zipWith (,) xs ys@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( min( n1, n2 ) )@ zip :: s a -> s b -> s (a,b) -- | Like 'zip', but combines three sequences into triples. -- -- > zip3 = -- > <(x0,y0,z0),...,(xj-1,yj-1,zj-1)> -- > where j = min {n,m,k} -- -- /Axioms:/ -- -- * @zip3 xs ys zs = zipWith3 (,,) xs ys zs@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( min( n1, n2, n3 ) )@ zip3 :: s a -> s b -> s c -> s (a,b,c) -- | Combine two sequences into a single sequence by mapping -- a combining function across corresponding elements. If -- the sequences are of different lengths, the excess elements -- of the longer sequence are discarded. -- -- > zipWith f xs ys = map (uncurry f) (zip xs ys) -- -- /Axioms:/ -- -- * @zipWith f (lcons x xs) (lcons y ys) = -- lcons (f x y) (zipWith f xs ys)@ -- -- * @(null xs || null ys) ==> zipWith xs ys = empty@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( t * min( n1, n2 ) )@ -- where @t@ is the running time of @f@ zipWith :: (a -> b -> c) -> s a -> s b -> s c -- | Like 'zipWith' but for a three-place function and three -- sequences. -- -- > zipWith3 f xs ys zs = map (uncurry f) (zip3 xs ys zs) -- -- /Axioms:/ -- -- * @zipWith3 (lcons x xs) (lcons y ys) (lcons z zs) = -- lcons (f x y z) (zipWith3 f xs ys zs)@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( t * min( n1, n2, n3 ) )@ -- where @t@ is the running time of @f@ zipWith3 :: (a -> b -> c -> d) -> s a -> s b -> s c -> s d -- | Transpose a sequence of pairs into a pair of sequences. -- -- > unzip xs = (map fst xs, map snd xs) -- -- /Axioms:/ -- -- * @unzip xys = unzipWith fst snd xys@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( n )@ unzip :: s (a,b) -> (s a, s b) -- | Transpose a sequence of triples into a triple of sequences -- -- > unzip3 xs = (map fst3 xs, map snd3 xs, map thd3 xs) -- > where fst3 (x,y,z) = x -- > snd3 (x,y,z) = y -- > thd3 (x,y,z) = z -- -- /Axioms:/ -- -- * @unzip3 xyzs = unzipWith3 fst3 snd3 thd3 xyzs@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( n )@ unzip3 :: s (a,b,c) -> (s a, s b, s c) -- | Map two functions across every element of a sequence, -- yielding a pair of sequences -- -- > unzipWith f g xs = (map f xs, map g xs) -- -- /Axioms:/ -- -- * @unzipWith f g xs = (map f xs, map g xs)@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( t * n )@ -- where @t@ is the maximum running time -- of @f@ and @g@ unzipWith :: (a -> b) -> (a -> c) -> s a -> (s b, s c) -- | Map three functions across every element of a sequence, -- yielding a triple of sequences. -- -- > unzipWith3 f g h xs = (map f xs, map g xs, map h xs) -- -- /Axioms:/ -- -- * @unzipWith3 f g h xs = (map f xs,map g xs,map h xs)@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( t * n )@ -- where @t@ is the maximum running time -- of @f@, @g@, and @h@ unzipWith3 :: (a -> b) -> (a -> c) -> (a -> d) -> s a -> (s b, s c, s d) -- | Semanticly, this function is a partial identity function. If the -- datastructure is infinite in size or contains exceptions or non-termination -- in the structure itself, then @strict@ will result in bottom. Operationally, -- this function walks the datastructure forcing any closures. Elements contained -- in the sequence are /not/ forced. -- -- /Axioms:/ -- -- * @strict xs = xs@ OR @strict xs = _|_@ -- -- This function is always /unambiguous/. -- -- Default running time: @O( n )@ strict :: s a -> s a -- | Similar to 'strict', this function walks the datastructure forcing closures. -- However, @strictWith@ will additionally apply the given function to the -- sequence elements, force the result using @seq@, and then ignore it. -- This function can be used to perform various levels of forcing on the -- sequence elements. In particular: -- -- > strictWith id xs -- -- will force the spine of the datastructure and reduce each element to WHNF. -- -- /Axioms:/ -- -- * forall @f :: a -> b@, @strictWith f xs = xs@ OR @strictWith f xs = _|_@ -- -- This function is always /unambiguous/. -- -- Default running time: unbounded (forcing element closures can take arbitrairly long) strictWith :: (a -> b) -> s a -> s a -- | A method to facilitate unit testing. Returns 'True' if the structural -- invariants of the implementation hold for the given sequence. If -- this function returns 'False', it represents a bug in the implementation. structuralInvariant :: s a -> Bool -- | The name of the module implementing s. instanceName :: s a -> String ---------------------------------------------------------------------- -- Other possible operations not currently included {- insertAt :: Int -> a -> s a -> s a -- adds to front or rear if index out of bounds -- -- insertAt i y xs@ -- | i < 0 = cons y xs -- | i >= n = snoc xs y -- | otherwise = deleteAt :: Int -> s a -> s a -- returns original sequence if index out of bounds -- -- deleteAt i xs@ -- | i < 0 = xs -- | i >= n = xs -- | otherwise = insertAt i x s = append before (cons x after) where (before, after) = splitAt i s deleteAt i s = if i < 0 then s else append before (ltail after) where (before, after) = splitAt i s -}