{-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE PolyKinds #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE RebindableSyntax #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-# OPTIONS_GHC -fplugin GHC.TypeLits.Normalise #-} -- | Statically verified, type-indexed, weight-biased leftist heaps. module Data.Queue.Indexed.Leftist (Leftist(..)) where import Data.Queue.Indexed.Class import Data.Type.Equality import Prelude import TypeLevel.Bool import TypeLevel.Singletons import Control.DeepSeq (NFData(rnf)) -- | A size-indexed weight-biased leftist heap. Somewhat based on -- the implementation from -- . -- -- Type-level natural numbers are used to maintain the invariants -- in the size of the structure, but these are backed by -- 'Numeric.Natural.Natural' at runtime, maintaining some -- efficiency. -- -- For instance, the '<=.' function is used, which compares two -- numbers (runtime integers), but provides a boolean singleton -- as its result: when matched on, this provides a /type-level-proof/ -- of the ordering. data Leftist n a where Leaf :: Leftist 0 a Node :: !(The Nat (n + m + 1)) -> a -> Leftist n a -> Leftist m a -> !(m <= n) -> Leftist (n + m + 1) a rank :: Leftist n s -> The Nat n rank Leaf = sing rank (Node r _ _ _ _) = r {-# INLINE rank #-} instance Ord a => IndexedQueue Leftist a where minView (Node _ x l r _) = (x, merge l r) {-# INLINE minView #-} singleton x = Node sing x Leaf Leaf Refl {-# INLINE singleton #-} empty = Leaf {-# INLINE empty #-} insert = merge . singleton {-# INLINE insert #-} minViewMay Leaf b _ = b minViewMay (Node _ x l r _) _ f = f x (merge l r) instance Ord a => MeldableIndexedQueue Leftist a where merge Leaf h2 = h2 merge h1 Leaf = h1 merge h1@(Node w1 p1 l1 r1 _) h2@(Node w2 p2 l2 r2 _) | p1 < p2 = if ll <=. lr then Node (w1 +. w2) p1 l1 (merge r1 h2) else Node (w1 +. w2) p1 (merge r1 h2) l1 . totalOrder ll lr | otherwise = if rl <=. rr then Node (w1 +. w2) p2 l2 (merge r2 h1) else Node (w1 +. w2) p2 (merge r2 h1) l2 . totalOrder rl rr where ll = rank r1 +. w2 lr = rank l1 rl = rank r2 +. w1 rr = rank l2 {-# INLINE merge #-} instance NFData a => NFData (Leftist n a) where rnf Leaf = () rnf (Node n x l r Refl) = n `seq` rnf x `seq` rnf l `seq` rnf r `seq` ()