-- Standard list functions -- build really shouldn't be exported, but what the heck. -- some of the helper functions in this file shouldn't be -- exported either! module PreludeList (PreludeList.., foldr, build) where import PreludePrims(build, foldr) {-#Prelude#-} -- Indicates definitions of compiler prelude symbols infixl 9 !! infix 5 \\ infixr 5 ++ infix 4 `elem`, `notElem` -- These are primitives used by the deforestation stuff in the optimizer. -- the optimizer will turn references to foldr and build into -- inlineFoldr and inlineBuild, respectively, but doesn't want to -- necessarily inline all references immediately. inlineFoldr :: (a -> b -> b) -> b -> [a] -> b inlineFoldr f z l = let foldr' [] = z foldr' (x:xs) = f x (foldr' xs) in foldr' l {-# inlineFoldr :: Inline #-} inlineBuild :: ((a -> [a] -> [a]) -> [b] -> [c]) -> [c] inlineBuild g = g (:) [] {-# inlineBuild :: Inline #-} -- head and tail extract the first element and remaining elements, -- respectively, of a list, which must be non-empty. last and init -- are the dual functions working from the end of a finite list, -- rather than the beginning. head :: [a] -> a head (x:_) = x head [] = error "head{PreludeList}: head []" last :: [a] -> a last [x] = x last (_:xs) = last xs last [] = error "last{PreludeList}: last []" tail :: [a] -> [a] tail (_:xs) = xs tail [] = error "tail{PreludeList}: tail []" init :: [a] -> [a] init [x] = [] init (x:xs) = x : init xs init [] = error "init{PreludeList}: init []" -- null determines if a list is empty. null :: [a] -> Bool null [] = True null (_:_) = False -- list concatenation (right-associative) (++) :: [a] -> [a] -> [a] xs ++ ys = build (\ c n -> foldr c (foldr c n ys) xs) {-# (++) :: Inline #-} -- the first occurrence of each element of ys in turn (if any) -- has been removed from xs. Thus, (xs ++ ys) \\ xs == ys. (\\) :: (Eq a) => [a] -> [a] -> [a] (\\) = foldl del where [] `del` _ = [] (x:xs) `del` y | x == y = xs | otherwise = x : xs `del` y -- length returns the length of a finite list as an Int; it is an instance -- of the more general genericLength, the result type of which may be -- any kind of number. genericLength :: (Num a) => [b] -> a genericLength l = foldr (\ x n -> 1 + n) 0 l --genericLength [] = 0 --genericLength (x:xs) = 1 + genericLength xs {-# genericLength :: Inline #-} length :: [a] -> Int length l = foldr (\ x n -> 1 + n) 0 l --length [] = 0 --length (x:xs) = 1 + length xs {-# length :: Inline #-} -- List index (subscript) operator, 0-origin (!!) :: (Integral a) => [b] -> a -> b l !! i = nth l (fromIntegral i) {-# (!!) :: Inline #-} nth :: [b] -> Int -> b nth l m = let f x g 0 = x f x g i = g (i - 1) fail _ = error "(!!){PreludeList}: index too large" in foldr f fail l m {-# nth :: Inline #-} --nth _ n | n < 0 = error "(!!){PreludeList}: negative index" --nth [] n = error "(!!){PreludeList}: index too large" --nth (x:xs) n -- | n == 0 = x -- | otherwise = nth xs (n - 1) --{-# nth :: Strictness("S,S") #-} -- map f xs applies f to each element of xs; i.e., map f xs == [f x | x <- xs]. map :: (a -> b) -> [a] -> [b] map f xs = build (\ c n -> foldr (\ a b -> c (f a) b) n xs) --map f [] = [] --map f (x:xs) = f x : map f xs {-# map :: Inline #-} -- filter, applied to a predicate and a list, returns the list of those -- elements that satisfy the predicate; i.e., -- filter p xs == [x | x <- xs, p x]. filter :: (a -> Bool) -> [a] -> [a] filter f xs = build (\ c n -> foldr (\ a b -> if f a then c a b else b) n xs) --filter p = foldr (\x xs -> if p x then x:xs else xs) [] {-# filter :: Inline #-} -- partition takes a predicate and a list and returns a pair of lists: -- those elements of the argument list that do and do not satisfy the -- predicate, respectively; i.e., -- partition p xs == (filter p xs, filter (not . p) xs). partition :: (a -> Bool) -> [a] -> ([a],[a]) partition p = foldr select ([],[]) where select x (ts,fs) | p x = (x:ts,fs) | otherwise = (ts,x:fs) {-# partition :: Inline #-} -- foldl, applied to a binary operator, a starting value (typically the -- left-identity of the operator), and a list, reduces the list using -- the binary operator, from left to right: -- foldl f z [x1, x2, ..., xn] == (...((z `f` x1) `f` x2) `f`...) `f` xn -- foldl1 is a variant that has no starting value argument, and thus must -- be applied to non-empty lists. scanl is similar to foldl, but returns -- a list of successive reduced values from the left: -- scanl f z [x1, x2, ...] == [z, z `f` x1, (z `f` x1) `f` x2, ...] -- Note that last (scanl f z xs) == foldl f z xs. -- scanl1 is similar, again without the starting element: -- scanl1 f [x1, x2, ...] == [x1, x1 `f` x2, ...] foldl :: (a -> b -> a) -> a -> [b] -> a foldl f z xs = foldr (\ b g a -> g (f a b)) id xs z --foldl f z [] = z --foldl f z (x:xs) = foldl f (f z x) xs {-# foldl :: Inline #-} foldl1 :: (a -> a -> a) -> [a] -> a foldl1 f (x:xs) = foldl f x xs foldl1 _ [] = error "foldl1{PreludeList}: empty list" {-# foldl1 :: Inline #-} scanl :: (a -> b -> a) -> a -> [b] -> [a] scanl f q xs = q : (case xs of [] -> [] x:xs -> scanl f (f q x) xs) {-# scanl :: Inline #-} scanl1 :: (a -> a -> a) -> [a] -> [a] scanl1 f (x:xs) = scanl f x xs scanl1 _ [] = error "scanl1{PreludeList}: empty list" {-# scanl1 :: Inline #-} -- foldr, foldr1, scanr, and scanr1 are the right-to-left duals of the -- above functions. --foldr :: (a -> b -> b) -> b -> [a] -> b --foldr f z [] = z --foldr f z (x:xs) = f x (foldr f z xs) foldr1 :: (a -> a -> a) -> [a] -> a foldr1 f [x] = x foldr1 f (x:xs) = f x (foldr1 f xs) foldr1 _ [] = error "foldr1{PreludeList}: empty list" {-# foldr1 :: Inline #-} -- I'm not sure the build/foldr expansion wins. scanr :: (a -> b -> b) -> b -> [a] -> [b] --scanr f q0 l = build (\ c n -> -- let g x qs@(q:_) = c (f x q) qs -- in foldr g (c q0 n) l) scanr f q0 [] = [q0] scanr f q0 (x:xs) = f x q : qs where qs@(q:_) = scanr f q0 xs {-# scanr :: Inline #-} scanr1 :: (a -> a -> a) -> [a] -> [a] scanr1 f [x] = [x] scanr1 f (x:xs) = f x q : qs where qs@(q:_) = scanr1 f xs scanr1 _ [] = error "scanr1{PreludeList}: empty list" {-# scanr1 :: Inline #-} -- iterate f x returns an infinite list of repeated applications of f to x: -- iterate f x == [x, f x, f (f x), ...] iterate :: (a -> a) -> a -> [a] iterate f x = build (\ c n -> let iterate' x' = c x' (iterate' (f x')) in iterate' x) --iterate f x = x : iterate f (f x) {-# iterate :: Inline #-} -- repeat x is an infinite list, with x the value of every element. repeat :: a -> [a] repeat x = build (\ c n -> let r = c x r in r) --repeat x = xs where xs = x:xs {-# repeat :: Inline #-} -- cycle ties a finite list into a circular one, or equivalently, -- the infinite repetition of the original list. It is the identity -- on infinite lists. cycle :: [a] -> [a] cycle xs = xs' where xs' = xs ++ xs' -- take n, applied to a list xs, returns the prefix of xs of length n, -- or xs itself if n > length xs. drop n xs returns the suffix of xs -- after the first n elements, or [] if n > length xs. splitAt n xs -- is equivalent to (take n xs, drop n xs). take :: (Integral a) => a -> [b] -> [b] take n l = takeInt (fromIntegral n) l {-# take :: Inline #-} takeInt :: Int -> [b] -> [b] takeInt m l = build (\ c n -> let f x g i | i <= 0 = n | otherwise = c x (g (i - 1)) in foldr f (\ _ -> n) l m) --takeInt 0 _ = [] --takeInt _ [] = [] --takeInt n l | n > 0 = primTake n l {-# takeInt :: Inline #-} -- Writing drop and friends in terms of build/foldr seems to lose -- way big since they cause an extra traversal of the list tail -- (except when the calls are being deforested). drop :: (Integral a) => a -> [b] -> [b] drop n l = dropInt (fromIntegral n) l {-# drop :: Inline #-} {-# drop :: Strictness("S,S") #-} dropInt :: Int -> [b] -> [b] dropInt 0 xs = xs dropInt _ [] = [] dropInt (n+1) (_:xs) = dropInt n xs {-# dropInt :: Inline #-} splitAt :: (Integral a) => a -> [b] -> ([b],[b]) splitAt n l = splitAtInt (fromIntegral n) l {-# splitAt :: Inline #-} splitAtInt :: Int -> [b] -> ([b],[b]) splitAtInt 0 xs = ([],xs) splitAtInt _ [] = ([],[]) splitAtInt (n+1) (x:xs) = (x:xs',xs'') where (xs',xs'') = splitAtInt n xs {-# splitAtInt :: Inline #-} -- takeWhile, applied to a predicate p and a list xs, returns the longest -- prefix (possibly empty) of xs of elements that satisfy p. dropWhile p xs -- returns the remaining suffix. Span p xs is equivalent to -- (takeWhile p xs, dropWhile p xs), while break p uses the negation of p. takeWhile :: (a -> Bool) -> [a] -> [a] takeWhile p l = build (\ c n -> foldr (\ a b -> if p a then c a b else n) n l) --takeWhile p [] = [] --takeWhile p (x:xs) -- | p x = x : takeWhile p xs -- | otherwise = [] {-# takeWhile :: Inline #-} dropWhile :: (a -> Bool) -> [a] -> [a] dropWhile p [] = [] dropWhile p xs@(x:xs') | p x = dropWhile p xs' | otherwise = xs {-# dropWhile :: Inline #-} span, break :: (a -> Bool) -> [a] -> ([a],[a]) span p [] = ([],[]) span p xs@(x:xs') | p x = let (ys,zs) = span p xs' in (x:ys,zs) | otherwise = ([],xs) break p = span (not . p) {-# span :: Inline #-} {-# break :: Inline #-} -- lines breaks a string up into a list of strings at newline characters. -- The resulting strings do not contain newlines. Similary, words -- breaks a string up into a list of words, which were delimited by -- white space. unlines and unwords are the inverse operations. -- unlines joins lines with terminating newlines, and unwords joins -- words with separating spaces. lines :: String -> [String] lines "" = [] lines s = let (l, s') = break (== '\n') s in l : case s' of [] -> [] (_:s'') -> lines s'' words :: String -> [String] words s = case dropWhile isSpace s of "" -> [] s' -> w : words s'' where (w, s'') = break isSpace s' unlines :: [String] -> String unlines = concat . map (++ "\n") {-# unlines :: Inline #-} unwords :: [String] -> String unwords [] = "" unwords ws = foldr1 (\w s -> w ++ ' ':s) ws -- nub (meaning "essence") removes duplicate elements from its list argument. nub :: (Eq a) => [a] -> [a] nub l = build (\ c n -> let f x g [] = c x (g [x]) f x g xs = if elem x xs then (g xs) else c x (g (x:xs)) in foldr f (\ _ -> n) l []) {-# nub :: Inline #-} --nub [] = [] --nub (x:xs) = x : nub (filter (/= x) xs) -- reverse xs returns the elements of xs in reverse order. xs must be finite. reverse :: [a] -> [a] reverse l = build (\ c n -> let f x g tail = g (c x tail) in foldr f id l n) {-# reverse :: Inline #-} --reverse x = reverse1 x [] where -- reverse1 [] a = a -- reverse1 (x:xs) a = reverse1 xs (x:a) -- and returns the conjunction of a Boolean list. For the result to be -- True, the list must be finite; False, however, results from a False -- value at a finite index of a finite or infinite list. or is the -- disjunctive dual of and. and, or :: [Bool] -> Bool and = foldr (&&) True or = foldr (||) False {-# and :: Inline #-} {-# or :: Inline #-} -- Applied to a predicate and a list, any determines if any element -- of the list satisfies the predicate. Similarly, for all. any, all :: (a -> Bool) -> [a] -> Bool any p = or . map p all p = and . map p {-# any :: Inline #-} {-# all :: Inline #-} -- elem is the list membership predicate, usually written in infix form, -- e.g., x `elem` xs. notElem is the negation. elem, notElem :: (Eq a) => a -> [a] -> Bool elem x ys = foldr (\ y t -> (x == y) || t) False ys --x `elem` [] = False --x `elem` (y:ys) = x == y || x `elem` ys {-# elem :: Inline #-} notElem x y = not (x `elem` y) -- sum and product compute the sum or product of a finite list of numbers. sum, product :: (Num a) => [a] -> a sum = foldl (+) 0 product = foldl (*) 1 {-# sum :: Inline #-} {-# product :: Inline #-} -- sums and products give a list of running sums or products from -- a list of numbers. For example, sums [1,2,3] == [0,1,3,6]. sums, products :: (Num a) => [a] -> [a] sums = scanl (+) 0 products = scanl (*) 1 -- maximum and minimum return the maximum or minimum value from a list, -- which must be non-empty, finite, and of an ordered type. maximum, minimum :: (Ord a) => [a] -> a maximum = foldl1 max minimum = foldl1 min {-# maximum :: Inline #-} {-# minimum :: Inline #-} -- concat, applied to a list of lists, returns their flattened concatenation. concat :: [[a]] -> [a] concat xs = build (\ c n -> foldr (\ x y -> foldr c y x) n xs) --concat [] = [] --concat (l:ls) = l ++ concat ls {-# concat :: Inline #-} -- transpose, applied to a list of lists, returns that list with the -- "rows" and "columns" interchanged. The input need not be rectangular -- (a list of equal-length lists) to be completely transposable, but can -- be "triangular": Each successive component list must be not longer -- than the previous one; any elements outside of the "triangular" -- transposable region are lost. The input can be infinite in either -- dimension or both. transpose :: [[a]] -> [[a]] transpose = foldr (\xs xss -> zipWith (:) xs (xss ++ repeat [])) [] {-# transpose :: Inline #-} -- zip takes two lists and returns a list of corresponding pairs. If one -- input list is short, excess elements of the longer list are discarded. -- zip3 takes three lists and returns a list of triples, etc. Versions -- of zip producing up to septuplets are defined here. zip :: [a] -> [b] -> [(a,b)] zip = zipWith (\a b -> (a,b)) {-# zip :: Inline #-} zip3 :: [a] -> [b] -> [c] -> [(a,b,c)] zip3 = zipWith3 (\a b c -> (a,b,c)) {-# zip3 :: Inline #-} zip4 :: [a] -> [b] -> [c] -> [d] -> [(a,b,c,d)] zip4 = zipWith4 (\a b c d -> (a,b,c,d)) {-# zip4 :: Inline #-} zip5 :: [a] -> [b] -> [c] -> [d] -> [e] -> [(a,b,c,d,e)] zip5 = zipWith5 (\a b c d e -> (a,b,c,d,e)) {-# zip5 :: Inline #-} zip6 :: [a] -> [b] -> [c] -> [d] -> [e] -> [f] -> [(a,b,c,d,e,f)] zip6 = zipWith6 (\a b c d e f -> (a,b,c,d,e,f)) {-# zip6 :: Inline #-} zip7 :: [a] -> [b] -> [c] -> [d] -> [e] -> [f] -> [g] -> [(a,b,c,d,e,f,g)] zip7 = zipWith7 (\a b c d e f g -> (a,b,c,d,e,f,g)) {-# zip7 :: Inline #-} -- The zipWith family generalises the zip family by zipping with the -- function given as the first argument, instead of a tupling function. -- For example, zipWith (+) is applied to two lists to produce the list -- of corresponding sums. zipWith :: (a->b->c) -> [a]->[b]->[c] zipWith z as bs = build (\ c' n' -> let f' a g' (b:bs) = c' (z a b) (g' bs) f' a g' _ = n' in foldr f' (\ _ -> n') as bs) --zipWith z (a:as) (b:bs) = z a b : zipWith z as bs --zipWith _ _ _ = [] {-# zipWith :: Inline #-} zipWith3 :: (a->b->c->d) -> [a]->[b]->[c]->[d] zipWith3 z as bs cs = build (\ c' n' -> let f' a g' (b:bs) (c:cs) = c' (z a b c) (g' bs cs) f' a g' _ _ = n' in foldr f' (\ _ _ -> n') as bs cs) {-# zipWith3 :: Inline #-} --zipWith3 z (a:as) (b:bs) (c:cs) -- = z a b c : zipWith3 z as bs cs --zipWith3 _ _ _ _ = [] zipWith4 :: (a->b->c->d->e) -> [a]->[b]->[c]->[d]->[e] zipWith4 z as bs cs ds = build (\ c' n' -> let f' a g' (b:bs) (c:cs) (d:ds) = c' (z a b c d) (g' bs cs ds) f' a g' _ _ _ = n' in foldr f' (\ _ _ _ -> n') as bs cs ds) {-# zipWith4 :: Inline #-} --zipWith4 z (a:as) (b:bs) (c:cs) (d:ds) -- = z a b c d : zipWith4 z as bs cs ds --zipWith4 _ _ _ _ _ = [] zipWith5 :: (a->b->c->d->e->f) -> [a]->[b]->[c]->[d]->[e]->[f] zipWith5 z as bs cs ds es= build (\ c' n' -> let f' a g' (b:bs) (c:cs) (d:ds) (e:es) = c' (z a b c d e) (g' bs cs ds es) f' a g' _ _ _ _ = n' in foldr f' (\ _ _ _ _ -> n') as bs cs ds es) {-# zipWith5 :: Inline #-} --zipWith5 z (a:as) (b:bs) (c:cs) (d:ds) (e:es) -- = z a b c d e : zipWith5 z as bs cs ds es --zipWith5 _ _ _ _ _ _ = [] zipWith6 :: (a->b->c->d->e->f->g) -> [a]->[b]->[c]->[d]->[e]->[f]->[g] zipWith6 z as bs cs ds es fs = build (\ c' n' -> let f' a g' (b:bs) (c:cs) (d:ds) (e:es) (f:fs) = c' (z a b c d e f) (g' bs cs ds es fs) f' a g' _ _ _ _ _ = n' in foldr f' (\ _ _ _ _ _ -> n') as bs cs ds es fs) {-# zipWith6 :: Inline #-} --zipWith6 z (a:as) (b:bs) (c:cs) (d:ds) (e:es) (f:fs) -- = z a b c d e f : zipWith6 z as bs cs ds es fs --zipWith6 _ _ _ _ _ _ _ = [] zipWith7 :: (a->b->c->d->e->f->g->h) -> [a]->[b]->[c]->[d]->[e]->[f]->[g]->[h] zipWith7 z as bs cs ds es fs gs = build (\ c' n' -> let f' a g' (b:bs) (c:cs) (d:ds) (e:es) (f:fs) (g:gs) = c' (z a b c d e f g) (g' bs cs ds es fs gs) f' a g' _ _ _ _ _ _ = n' in foldr f' (\ _ _ _ _ _ _ -> n') as bs cs ds es fs gs) {-# zipWith7 :: Inline #-} --zipWith7 z (a:as) (b:bs) (c:cs) (d:ds) (e:es) (f:fs) (g:gs) -- = z a b c d e f g : zipWith7 z as bs cs ds es fs gs --zipWith7 _ _ _ _ _ _ _ _ = [] -- unzip transforms a list of pairs into a pair of lists. As with zip, -- a family of such functions up to septuplets is provided. unzip :: [(a,b)] -> ([a],[b]) unzip = foldr (\(a,b) ~(as,bs) -> (a:as,b:bs)) ([],[]) {-# unzip :: Inline #-} unzip3 :: [(a,b,c)] -> ([a],[b],[c]) unzip3 = foldr (\(a,b,c) ~(as,bs,cs) -> (a:as,b:bs,c:cs)) ([],[],[]) {-# unzip3 :: Inline #-} unzip4 :: [(a,b,c,d)] -> ([a],[b],[c],[d]) unzip4 = foldr (\(a,b,c,d) ~(as,bs,cs,ds) -> (a:as,b:bs,c:cs,d:ds)) ([],[],[],[]) {-# unzip4 :: Inline #-} unzip5 :: [(a,b,c,d,e)] -> ([a],[b],[c],[d],[e]) unzip5 = foldr (\(a,b,c,d,e) ~(as,bs,cs,ds,es) -> (a:as,b:bs,c:cs,d:ds,e:es)) ([],[],[],[],[]) {-# unzip5 :: Inline #-} unzip6 :: [(a,b,c,d,e,f)] -> ([a],[b],[c],[d],[e],[f]) unzip6 = foldr (\(a,b,c,d,e,f) ~(as,bs,cs,ds,es,fs) -> (a:as,b:bs,c:cs,d:ds,e:es,f:fs)) ([],[],[],[],[],[]) {-# unzip6 :: Inline #-} unzip7 :: [(a,b,c,d,e,f,g)] -> ([a],[b],[c],[d],[e],[f],[g]) unzip7 = foldr (\(a,b,c,d,e,f,g) ~(as,bs,cs,ds,es,fs,gs) -> (a:as,b:bs,c:cs,d:ds,e:es,f:fs,g:gs)) ([],[],[],[],[],[],[]) {-# unzip7 :: Inline #-}