packages feed

lambdabot-4.0: scripts/Djinn/Util/Sort.hs

{- Copyright (c) 2001,2002 Galois Connections, Inc.
 -}
{- |
 
  Module      :  Util.Sort
  Copyright   :  (c) Galois Connections 2001, 2002

  Maintainer      : lib@galois.com
  Stability       : 
  Portability     : 
  
  Extra sorting functions - copied from GHC compiler sources (util\/Util.lhs)
-}
module Util.Sort where

sortLt :: (a -> a -> Bool) 		-- Less-than predicate
       -> [a] 				-- Input list
       -> [a]				-- Result list

sortLt lt l = qsort lt l []

-- qsort is stable and does not concatenate.
qsort :: (a -> a -> Bool) -- Less-than predicate
      -> [a]		  -- xs, Input list
      -> [a]              -- r,  Concatenate this list to the sorted input list
      -> [a]		  -- Result = sort xs ++ r

qsort _  []     r = r
qsort _  [x]    r = x:r
qsort lt (x:xs) r = qpart lt x xs [] [] r

-- qpart partitions and sorts the sublists
-- rlt contains things less than x,
-- rge contains the ones greater than or equal to x.
-- Both have equal elements reversed with respect to the original list.

qpart :: (a -> a -> Bool) -> a -> [a] -> [a] -> [a] -> [a] -> [a]
qpart lt x [] rlt rge r =
    -- rlt and rge are in reverse order and must be sorted with an
    -- anti-stable sorting
    rqsort lt rlt (x : rqsort lt rge r)

qpart lt x (y:ys) rlt rge r =
    if lt y x then
	-- y < x
	qpart lt x ys (y:rlt) rge r
    else
	-- y >= x
	qpart lt x ys rlt (y:rge) r

-- rqsort is as qsort but anti-stable, i.e. reverses equal elements
rqsort :: (a -> a -> Bool)    -- Less-than predicate
       -> [a]		      -- xs, Input list
       -> [a]		      -- r,  Concatenate this list to the sorted input
       -> [a]		      -- Result = sort xs ++ r
rqsort _ []      r = r
rqsort _ [x]     r = x:r
rqsort lt (x:xs) r = rqpart lt x xs [] [] r

rqpart :: (a -> a -> Bool) -> a -> [a] -> [a] -> [a] -> [a] -> [a]
rqpart lt x [] rle rgt r =
    qsort lt rle (x : qsort lt rgt r)

rqpart lt x (y:ys) rle rgt r =
    if lt x y then
	-- y > x
	rqpart lt x ys rle (y:rgt) r
    else
	-- y <= x
	rqpart lt x ys (y:rle) rgt r

sortLe :: (a->a->Bool) -> [a] -> [a]
sortLe le = generalNaturalMergeSort le

mergeSort, naturalMergeSort :: Ord a => [a] -> [a]
mergeSort = generalMergeSort (<=)
naturalMergeSort = generalNaturalMergeSort (<=)

generalMergeSort :: (a->a->Bool) -> [a] -> [a]
generalMergeSort _ [] = []
generalMergeSort p xs = (balancedFold (generalMerge p) . map (: [])) xs

generalMerge :: (a -> a -> Bool) -> [a] -> [a] -> [a]
generalMerge _ xs [] = xs
generalMerge _ [] ys = ys
generalMerge p (x:xs) (y:ys) | x `p` y   = x : generalMerge p xs (y:ys)
			     | otherwise = y : generalMerge p (x:xs) ys

balancedFold :: (a -> a -> a) -> [a] -> a
balancedFold _ [] = error "Util.Sort.balancedFold: can't reduce an empty list"
balancedFold _ [x] = x
balancedFold f l  = balancedFold f (balancedFold' f l)

balancedFold' :: (a -> a -> a) -> [a] -> [a]
balancedFold' f (x:y:xs) = f x y : balancedFold' f xs
balancedFold' _ xs = xs

generalNaturalMergeSort :: (a -> a -> Bool) -> [a] -> [a]
generalNaturalMergeSort _   [] = []
generalNaturalMergeSort prd rs = (balancedFold (generalMerge prd) . group prd) rs
  where
   --group :: (a -> a -> Bool) -> [a] -> [[a]]
   group _ []     = []
   group p (l:ls) = group' ls l l (l:)
    where
     group' []     _     _     s  = [s []]
     group' (x:xs) x_min x_max s 
	| not (x `p` x_max) = group' xs x_min x (s . (x :)) 
	| x `p` x_min       = group' xs x x_max ((x :) . s) 
	| otherwise         = s [] : group' xs x x (x :)