module StackSet () where

import Data.Set (Set(..))

data LL a = Nil | Cons { headC :: a
                       , tailC :: LL a
                       }

{-@ data LL a = Nil | Cons { headC :: a
                           , tailC :: {v: LL a | not (Set_mem headC (elts v)) }
                           }
  @-}

{-@ measure elts :: LL a -> (Set a)
    elts (Nil)       = {v | (Set_emp v)}
    elts (Cons x xs) = {v | v = (Set_cup (Set_sng x) (elts xs)) }
  @-}

{-@ predicate Disjoint X Y = (Set_emp (Set_cap (elts X) (elts Y))) @-}
{-@ predicate NotIn    X Y = not (Set_mem X (elts Y))              @-}

ll2 = Cons x0 (Cons x1 (Cons x2 Nil))
  where x0 :: Int
        x0  = 0
        x1  = 1
        x2  = 2

{-@ data Stack a = St { focus  :: a
                      , up     :: {vu: LL a | (NotIn focus vu) }
                      , down   :: {vd: LL a | ((NotIn focus vd) && (Disjoint up vd)) }
                      }
  @-}

data Stack a = St { focus  :: !a
                  , up     :: !(LL a)
                  , down   :: !(LL a)
                  }

{-@ fresh :: a -> Stack a @-}
fresh x = St x Nil Nil

{-@ moveUp :: Stack a -> Stack a @-}
moveUp (St x (Cons y ys) zs) = St y ys (Cons x zs)
moveUp s                     = s

{-@ moveDn :: Stack a -> Stack a @-}
moveDn (St x ys (Cons z zs)) = St z (Cons x ys) zs
moveDn s                     = s