PPrel.hs revision 4959c4e13acd09856d0563ad72de17cfe2af89ba
module PPrel where
-- Standard types, classes, instances and related functions
-- Numeric classes
class (Num a, Ord a) => RealK a where
toRational' :: a -> Rational
class (RealK a, Enum a) => IntegralK a where
quot', rem' :: a -> a -> a
div', mod' :: a -> a -> a
quotRem', divMod' :: a -> a -> (a,a)
toInteger' :: a -> Integer
-- Minimal complete definition:
-- quotRem, toInteger
n `quot'` d = fst (quotRem' n d)
n `rem'` d = snd (quotRem' n d)
n `div'` d = fst (divMod' n d)
n `mod'` d = snd (divMod' n d)
divMod' n d = let qr = quotRem' n d
q = fst qr
r = snd qr
in if signum r == (0 - signum d) then
(q - 1, r + d) else quotRem' n d
-- if signum r == - signum d then (q-1, r+d)
-- else quotRem n d
class (Num a) => FractionalK a where
(/#) :: a -> a -> a
recip' :: a -> a
fromRational' :: Rational -> a
-- Minimal complete definition:
-- fromRational and (recip or (/))
recip' x = 1 /# x
x /# y = x * recip' y
-- Numeric functions
-- subtract' :: (Num a) => a -> a -> a
-- subtract' = flip' (-)
even', odd' :: (IntegralK a) => a -> Bool
even' n = n `rem'` 2 == 0
odd' = not . even'
gcd' :: (IntegralK a) => a -> a -> a
gcd' 0 0 = error "Prelude.gcd: gcd 0 0 is undefined"
gcd' x y = gcdH (abs x) (abs y)
gcdH :: (IntegralK a) => a -> a -> a
gcdH x 0 = x
gcdH x y = gcdH y (x `rem'` y)
lcm' :: (IntegralK a) => a -> a -> a
lcm' _ 0 = 0
lcm' 0 _ = 0
lcm' x y = abs ((x `quot'` (gcd' x y)) * y)
(^#) :: (Num a, IntegralK b) => a -> b -> a
x ^# 0 = 1
x ^# n | n > 0 = powAux x (n - 1) x
_ ^# _ = error "Prelude.^: negative exponent"
powAux :: (Num a, IntegralK b) => a -> b -> a -> a
powAux _ 0 y = y
powAux x n y = powBux x n y
powBux :: (Num a, IntegralK b) => a -> b -> a -> a
powBux x n y | even' n = powBux (x * x) (n `quot'` 2) y
| otherwise' = powAux x (n - 1) (x * y)
(^^#) :: (FractionalK a, IntegralK b) => a -> b -> a
x ^^# n = if n >= 0 then x ^# n else recip' (x ^# (0 - n))
fromIntegral' :: (IntegralK a, Num b) => a -> b
fromIntegral' = fromInteger . toInteger'
realToFrac' :: (RealK a, FractionalK b) => a -> b
realToFrac' = fromRational' . toRational'
-- Trivial type
-- data () = () deriving (Eq, Ord, Enum, Bounded)
-- Not legal Haskell; for illustration only
-- Function type
-- identity function
id' :: a -> a
id' x = x
-- constant function
const' :: a -> b -> a
const' x _ = x
-- function composition
-- (.) :: (b -> c) -> (a -> b) -> a -> c
-- f . g = \ x -> f (g x)
-- flip f takes its (first) two arguments in the reverse order of f.
-- flip' :: (a -> b -> c) -> b -> a -> c
-- flip' f x y = f y x
{-
seq :: a -> b -> b
seq = ... -- Primitive
-}
-- right-associating infix application operators
-- (useful in continuation-passing style)
-- ($), ($!) :: (a -> b) -> a -> b
-- f $ x = f x
-- f $! x = P.seq x (f x)
-- Boolean type
-- Boolean functions
otherwise' :: Bool
otherwise' = True
-- primIntToChar = undefined'
-- primCharToInt = undefined'
-- primUnicodeMaxChar = undefined'
maybe' :: b -> (a -> b) -> Maybe a -> b
maybe' n f Nothing = n
maybe' n f (Just x) = f x
either' :: (a -> c) -> (b -> c) -> Either a b -> c
either' f g (Left x) = f x
either' f g (Right y) = g y
-- curry converts an uncurried function to a curried function;
-- uncurry converts a curried function to a function on pairs.
curry' :: ((a, b) -> c) -> a -> b -> c
curry' f x y = f (x, y)
uncurry' :: (a -> b -> c) -> ((a, b) -> c)
uncurry' f p = f (fst p) (snd p)
-- Misc functions
-- until p f yields the result of applying f until p holds.
until' :: (a -> Bool) -> (a -> a) -> a -> a
until' p f x
| p x = x
| otherwise' = until' p f (f x)
-- asTypeOf is a type-restricted version of const. It is usually used
-- as an infix operator, and its typing forces its first argument
-- (which is usually overloaded) to have the same type as the second.
asTypeOf' :: a -> a -> a
asTypeOf' = const'
-- error stops execution and displays an error message
-- error' :: String -> a
-- error' = primError
-- It is expected that compilers will recognize this and insert error
-- messages that are more appropriate to the context in which undefined
-- appears.
undefined' :: a
undefined' = error "Prelude.undefined"
-- Standard list functions
-- Map and append
head' :: [a] -> a
head' (x:_) = x
head' [] = error "Prelude.head: empty list"
tail' :: [a] -> [a]
tail' (_:xs) = xs
tail' [] = error "Prelude.tail: empty list"
-- map' :: (a -> b) -> [a] -> [b]
-- map' f [] = []
-- map' f (x:xs) = f x : map' f xs
(++#) :: [a] -> [a] -> [a]
[] ++# ys = ys
(x:xs) ++# ys = x : (xs ++# ys)
filter' :: (a -> Bool) -> [a] -> [a]
filter' p [] = []
filter' p (x:xs) | p x = x : filter' p xs
| otherwise' = filter' p xs
concat' :: [[a]] -> [a]
concat' xss = foldr' (++#) [] xss
concatMap' :: (a -> [b]) -> [a] -> [b]
concatMap' f = concat' . map f
-- 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.
last' :: [a] -> a
last' [x] = x
last' (_:xs) = last' xs
last' [] = error "Prelude.last: empty list"
init' :: [a] -> [a]
init' [x] = []
init' (x:xs) = x : init' xs
init' [] = error "Prelude.init: empty list"
null' :: [a] -> Bool
null' [] = True
null' (_:_) = False
-- length returns the length of a finite list as an Int.
length' :: [a] -> Int
length' [] = 0
length' (_:l) = 1 + length' l
-- List index (subscript) operator, 0-origin
(!!#) :: [a] -> Int -> a
xs !!# n | n < 0 = error "Prelude.!!: negative index"
[] !!# _ = error "Prelude.!!: index too large"
(x:_) !!# 0 = x
(_:xs) !!# n = xs !!# (n - 1)
-- 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 [] = z
foldl' f z (x:xs) = foldl' f (f z x) xs
foldl1' :: (a -> a -> a) -> [a] -> a
foldl1' f (x:xs) = foldl' f x xs
foldl1' _ [] = error "Prelude.foldl1: empty list"
scanl' :: (a -> b -> a) -> a -> [b] -> [a]
scanl' f q xs = q : (case xs of
[] -> []
x:xs -> scanl' f (f q x) xs)
scanl1' :: (a -> a -> a) -> [a] -> [a]
scanl1' f (x:xs) = scanl' f x xs
scanl1' _ [] = []
-- 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 "Prelude.foldr1: empty list"
scanr' :: (a -> b -> b) -> b -> [a] -> [b]
scanr' f q0 [] = [q0]
scanr' f q0 (x:xs) = let qs = scanr' f q0 xs
in f x (head' qs) : qs
-- where qs@(q:_) = scanr f q0 xs
scanr1' :: (a -> a -> a) -> [a] -> [a]
scanr1' f [] = []
scanr1' f [x] = [x]
scanr1' f (x:xs) = let qs = scanr1' f xs
in f x (head' qs) : qs
-- 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 = x : iterate' f (f x)
-- repeat x is an infinite list, with x the value of every element.
repeat' :: a -> [a]
repeat' x = x: (repeat' x)
-- replicate n x is a list of length n with x the value of every element
replicate' :: Int -> a -> [a]
replicate' n x = take' n (repeat' x)
-- 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' [] = error "Prelude.cycle: empty list"
cycle' xs = xs ++# cycle' xs
-- 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' :: Int -> [a] -> [a]
take' n _ | n <= 0 = []
take' _ [] = []
take' n (x:xs) = x : take' (n - 1) xs
drop' :: Int -> [a] -> [a]
drop' n xs | n <= 0 = xs
drop' _ [] = []
drop' n (_:xs) = drop' (n - 1) xs
splitAt' :: Int -> [a] -> ([a],[a])
splitAt' n xs = (take' n xs, drop' n xs)
-- 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 [] = []
takeWhile' p (x:xs)
| p x = x : takeWhile' p xs
| otherwise' = []
dropWhile' :: (a -> Bool) -> [a] -> [a]
dropWhile' p [] = []
dropWhile' p (x:xs)
| p x = dropWhile' p xs
| otherwise' = x:xs
span', break' :: (a -> Bool) -> [a] -> ([a],[a])
span' p [] = ([],[])
span' p (x:xs)
| p x = let yz = span' p xs
in (x:(fst yz), snd yz)
| otherwise' = ([],x:xs)
-- | p x = (x:ys,zs)
-- where (ys,zs) = span p xs
break' p = span' (not . p)
-- 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.
-- isSpace' :: Char -> Bool
-- isSpace' c = elem' c " \t\n\r\f\v\xA0"
lines' :: String -> [String]
lines' s = if s == "" then []
else let ls = break' (== '\n') s
l = fst ls
s' = snd ls
in l : case s' of
[] -> []
(_:s'') -> lines' s''
{-
words' :: String -> [String]
words' s = let s' = dropWhile' isSpace' s
in if s' == "" then []
else let ws = break' isSpace' s'
in (fst ws) : words' (snd ws)
-}
-- unlines' :: [String] -> String
-- unlines' = concatMap' (++# "\n")
{-
unwords' :: [String] -> String
unwords' [] = ""
unwords' ws = foldr1' (\w s -> w ++# (' ':s)) ws
-}
-- reverse xs returns the elements of xs in reverse order. xs must be finite.
reverse' :: [a] -> [a]
reverse' = foldl' (flip (:)) []
-- 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
-- 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
-- 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 = any' (== x)
notElem' x = all' (/= x)
-- lookup key assocs looks up a key in an association list.
lookup' :: (Eq a) => a -> [(a,b)] -> Maybe b
lookup' key [] = Nothing
lookup' key (xy : xys)
| key == fst xy = Just (snd xy)
| otherwise' = lookup' key xys
-- 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
-- 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' [] = error "Prelude.maximum: empty list"
maximum' xs = foldl1' max xs
minimum' [] = error "Prelude.minimum: empty list"
minimum' xs = foldl1' min xs
-}
-- 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. Zips for larger
-- tuples are in the List library
zip' :: [a] -> [b] -> [(a,b)]
zip' = zipWith' (,)
-- 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 (a:as) (b:bs)
= z a b : zipWith' z as bs
zipWith' _ _ _ = []
-- unzip transforms a list of pairs into a pair of lists.
unzip' :: [(a,b)] -> ([a],[b])
unzip' = foldr' (\x xs -> ((fst x):
(fst xs),(snd x):(snd xs))) ([],[])