Ei kuvausta

DataStructures.hs 4.0KB

    {-| Module: DataStructures Description: Having fun with (functional) data structures Inspired by: * Purely Functional Data Structures, by Chris Okasaki * <http://www.infoq.com/presentations/Functional-Data-Structures-in-Scala Functional Data Structures in Scala>, by Daniel Spiewak -} module DataStructures where import Prelude hiding (concat, drop, last, length, reverse, take) class Seq s where first :: s a -> Maybe a last :: s a -> Maybe a last s | isEmpty s = Nothing last s | isEmpty (rest s) = case first s of Just x -> Just x last s = last $ rest s cons :: a -> s a -> s a nil :: s a rest :: s a -> s a length :: s a -> Integer length s | isEmpty s = 0 length s = 1 + length (rest s) isEmpty :: s a -> Bool fromList :: (Seq s) => [a] -> s a fromList [] = nil fromList (x:xs) = cons x $ fromList xs butLast :: (Seq s) => s a -> s a butLast s | isEmpty s = nil butLast s = case first s of Just x -> cons x $ butLast (rest s) drop :: (Seq s) => Integer -> s a -> s a drop 0 s = s drop _ s | isEmpty s = nil drop n s = drop (n-1) $ rest s take :: (Seq s) => Integer -> s a -> s a take 0 _ = nil take n s = case first s of Nothing -> nil Just x -> cons x $ take (n-1) (rest s) append :: (Seq s) => a -> s a -> s a append x s | isEmpty s = cons x nil append x s = case first s of Just x -> cons x $ append x (rest s) concat :: (Seq s) => s a -> s a -> s a concat l r | isEmpty l = r concat l r | isEmpty r = l concat l r = case first l of Just x -> cons x $ concat (rest l) r reverse :: (Seq s) => s a -> s a reverse s = rev s nil where rev l r | isEmpty l = r rev l r = case first l of Nothing -> nil Just x -> rev (rest l) $ cons x r instance Seq [] where first [] = Nothing first (x:_) = Just x cons x xs = x:xs nil = [] rest [] = [] rest (_:xs) = xs isEmpty [] = True isEmpty _ = False data List a = Nil | Cons a (List a) deriving Show -- first and cons are O(1), everything else is O(n) instance Seq List where first Nil = Nothing first (Cons x _) = Just x cons x l = Cons x l nil = Nil rest Nil = Nil rest (Cons _ l) = l isEmpty Nil = True isEmpty _ = False -- fifo, remove from front, insert into rear data BankersQueue a = BankersQueue { frontSize :: Integer, front :: List a, rearSize :: Integer, rear :: List a } deriving (Show) enqueue x (BankersQueue fs f rs r) = check $ BankersQueue fs f (rs + 1) (cons x r) dequeue (BankersQueue fs Nil rs Nil) = Nothing dequeue (BankersQueue fs Nil rs r) = Just (x, check $ BankersQueue fs Nil (rs - 1) r') where (Just x) = last r r' = butLast r dequeue (BankersQueue fs (Cons x fr) rs r) = Just (x, check $ BankersQueue (fs - 1) fr rs r) dequeueN 0 q = Nothing dequeueN 1 q = dequeue q >>= \(x, _) -> return x dequeueN n q = dequeue q >>= \(_, q') -> dequeueN (n-1) q' check q@(BankersQueue fs f rs r) = if rs <= fs then q else BankersQueue (fs + rs) (f `concat` reverse r) 0 Nil instance Seq BankersQueue where first (BankersQueue _ Nil _ r) = last r first (BankersQueue _ (Cons x _) _ _) = Just x -- O(1) amortized last (BankersQueue _ f _ Nil) = last f last (BankersQueue _ _ _ r) = first r cons x q = enqueue x q nil = BankersQueue 0 Nil 0 Nil rest q | isEmpty q = nil rest q = case dequeue q of Nothing -> nil Just (_, q') -> q' length (BankersQueue fs _ rs _) = fs + rs isEmpty (BankersQueue _ Nil _ Nil) = True isEmpty _ = False -- examples sl = fromList [1..10] :: List Integer bq = fromList [1..10] :: BankersQueue Integer -- properties -- rest nil == nil -- (reverse . reverse) s == s -- first [s] == last [s]