KiCS-0.8.8: src/lib/Curry/Module/Sort.curry
------------------------------------------------------------------------------
--- A collection of useful functions for sorting and comparing
--- characters, strings, and lists.
---
--- @author Michael Hanus
--- @version February 2004
------------------------------------------------------------------------------
module Sort(quickSort,mergeSort,
cmpChar, cmpList, cmpString,
leqChar, leqCharIgnoreCase,leqList,
leqString,leqStringIgnoreCase,leqLexGerman) where
import Char
--- Quicksort.
quickSort :: (a -> a -> Bool) -> [a] -> [a]
quickSort _ [] = []
quickSort leq (x:xs) = let (l,r) = split x xs
in quickSort leq l ++ (x:quickSort leq r)
where
split _ [] = ([],[])
split e (y:ys) | leq y e = (y:l,r)
| otherwise = (l,y:r)
where (l,r) = split e ys
--- Bottom-up mergesort.
mergeSort :: (a -> a -> Bool) -> [a] -> [a]
mergeSort leq zs = mergeLists (genRuns zs)
where
-- generate runs of length 2:
genRuns [] = []
genRuns [x] = [[x]]
genRuns (x1:x2:xs) | leq x1 x2 = [x1,x2] : genRuns xs
| otherwise = [x2,x1] : genRuns xs
-- merge the runs:
mergeLists [] = []
mergeLists [x] = x
mergeLists (x1:x2:xs) = mergeLists (merge leq x1 x2 : mergePairs xs)
mergePairs [] = []
mergePairs [x] = [x]
mergePairs (x1:x2:xs) = merge leq x1 x2 : mergePairs xs
--- Merges two lists with respect to an ordering predicate.
merge :: (a -> a -> Bool) -> [a] -> [a] -> [a]
merge _ [] ys = ys
merge _ (x:xs) [] = x : xs
merge leq (x:xs) (y:ys) | leq x y = x : merge leq xs (y:ys)
| otherwise = y : merge leq (x:xs) ys
--------------------------------------------------------------------
-- Comparing lists, characters and strings
--- Less-or-equal on lists.
leqList :: (a -> a -> Bool) -> [a] -> [a] -> Bool
leqList _ [] _ = True
leqList _ (_:_) [] = False
leqList leq (x:xs) (y:ys) | x == y = leqList leq xs ys
| otherwise = leq x y
--- Comparison of lists.
cmpList :: (a -> a -> Ordering) -> [a] -> [a] -> Ordering
cmpList _ [] [] = EQ
cmpList _ [] (_:_) = LT
cmpList _ (_:_) [] = GT
cmpList cmp (x:xs) (y:ys) | cmp x y == EQ = cmpList cmp xs ys
| otherwise = cmp x y
--- Less-or-equal on characters.
leqChar :: Char -> Char -> Bool
leqChar c1 c2 = ord c1 <= ord c2
--- Comparison of characters.
cmpChar :: Char -> Char -> Ordering
cmpChar c1 c2 = if c1==c2 then EQ else if ord c1 < ord c2 then LT else GT
--- Less-or-equal on characters ignoring case considerations.
leqCharIgnoreCase :: Char -> Char -> Bool
leqCharIgnoreCase c1 c2 = ord (toUpper c1) <= ord (toUpper c2)
--- Less-or-equal on strings.
leqString :: String -> String -> Bool
leqString = leqList leqChar
--- Comparison of strings.
cmpString :: String -> String -> Ordering
cmpString = cmpList cmpChar
--- Less-or-equal on strings ignoring case considerations.
leqStringIgnoreCase :: String -> String -> Bool
leqStringIgnoreCase = leqList leqCharIgnoreCase
--- Lexicographical ordering on German strings.
--- Thus, upper/lowercase are not distinguished and Umlauts are sorted
--- as vocals.
leqLexGerman :: String -> String -> Bool
leqLexGerman [] _ = True
leqLexGerman (_:_) [] = False
leqLexGerman (x:xs) (y:ys) | x' == y' = leqLexGerman xs ys
| otherwise = x' < y'
where
x' = glex (ord x)
y' = glex (ord y)
-- map umlauts to vocals and make everything lowercase:
glex o | o >= ord 'A' && o <= ord 'Z' = o + (ord 'a' - ord 'A')
| o == 228 = ord 'a'
| o == 246 = ord 'o'
| o == 252 = ord 'u'
| o == 196 = ord 'a'
| o == 214 = ord 'o'
| o == 220 = ord 'u'
| o == 223 = ord 's'
| otherwise = o
-- end module Sort