module Data.Order.Algorithm.Raw.Dumb (
OrderCell,
ElementCell,
rawAlgorithm
) where
import Control.Applicative
import Control.Monad.ST
import Data.Order.Algorithm.Raw
import Data.Ratio
import Data.Set (Set)
import qualified Data.Set as Set
import Data.STRef
newtype OrderCell s = OrderCell (Set Label)
newtype ElementCell s = ElementCell Label
type Label = Rational
rawAlgorithm :: RawAlgorithm s OrderCell ElementCell
rawAlgorithm = RawAlgorithm {
newOrder = newSTRef (OrderCell Set.empty),
compareElements = \ rawElem1 rawElem2 _ -> do
ElementCell label1 <- readSTRef rawElem1
ElementCell label2 <- readSTRef rawElem2
return (compare label1 label2),
newMinimum = fromPureInsert pureInsertMinimum,
newMaximum = fromPureInsert pureInsertMaximum,
newAfter = relative fromPureInsert pureInsertAfter,
newBefore = relative fromPureInsert pureInsertBefore,
delete = relative fromPure pureDelete
}
fromPure :: (OrderCell s -> (a, OrderCell s))
-> RawOrder s OrderCell
-> ST s a
fromPure trans rawOrder = do
orderCell <- readSTRef rawOrder
let (output, orderCell') = trans orderCell
writeSTRef rawOrder orderCell'
return output
fromPureInsert :: (OrderCell s -> ElementCell s)
-> RawOrder s OrderCell
-> ST s (RawElement s ElementCell)
fromPureInsert trans rawOrder = fromPure trans' rawOrder >>= newSTRef where
trans' orderCell@(OrderCell labels) = (elemCell, orderCell') where
elemCell@(ElementCell label) = trans orderCell
orderCell'= OrderCell (Set.insert label labels)
relative :: ((OrderCell s -> a) -> RawOrder s OrderCell -> ST s b)
-> (ElementCell s -> OrderCell s -> a)
-> RawElement s ElementCell
-> RawOrder s OrderCell
-> ST s b
relative conv trans rawElem rawOrder = do
elemCell <- readSTRef rawElem
conv (trans elemCell) rawOrder
pureInsertMinimum :: OrderCell s -> ElementCell s
pureInsertMinimum (OrderCell labels) = ElementCell label where
label | Set.null labels = 1 % 2
| otherwise = Set.findMin labels / 2
pureInsertMaximum :: OrderCell s -> ElementCell s
pureInsertMaximum (OrderCell labels) = ElementCell label where
label | Set.null labels = 1 % 2
| otherwise = (Set.findMax labels + 1) / 2
pureInsertAfter :: ElementCell s -> OrderCell s -> ElementCell s
pureInsertAfter (ElementCell label)
(OrderCell labels) = ElementCell label' where
greater = snd (Set.split label labels)
label' | Set.null greater = (label + 1) / 2
| otherwise = (label + Set.findMin greater) / 2
pureInsertBefore :: ElementCell s -> OrderCell s -> ElementCell s
pureInsertBefore (ElementCell label)
(OrderCell labels) = ElementCell label' where
lesser = fst (Set.split label labels)
label' | Set.null lesser = label / 2
| otherwise = (label + Set.findMax lesser) / 2
pureDelete :: ElementCell s -> OrderCell s -> ((), OrderCell s)
pureDelete (ElementCell label)
(OrderCell labels) = ((), OrderCell labels') where
labels' = Set.delete label labels