home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-09-27 | 18.8 KB | 598 lines | [TEXT/YHS2] |
- -- 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 :: AlwaysInline #-}
-
-
- inlineBuild :: ((a -> [a] -> [a]) -> [b] -> [c]) -> [c]
- inlineBuild g = g (:) []
- {-# inlineBuild :: AlwaysInline #-}
-
-
- -- 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 _ = nthError m
- in foldr f fail l m
-
- nthError m = error ("(!!){PreludeList}: index " ++ show m ++ " out of range\n")
-
- {-# 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 #-}
-
- -- 1.3 Proposed Extensions
-
- copy :: Int -> a -> [a]
- copy n x = take n (repeat x)
-
- lookup :: Eq a => [(a,b)] -> a -> Maybe b
- lookup [] _ = Nothing
- lookup ((key,val) : rest) x | key == x = Just val
- | otherwise = lookup rest x
-