{-# LANGUAGE GADTs, ExistentialQuantification, EmptyDataDecls #-}
module SList where
data Safe
data Unsafe
-- Reimplemention of standard list constructors
-- instead of wrapping
-- Also switching the order of arguments to make
-- casting easier.
data List a b where
Nil :: List Unsafe b
Cons :: b ->(List c b) -> List Safe b
instance Show b => Show (List a b) where
show (Nil ) = "nil"
show (Cons x xs) = "(cons " ++ show x ++ " " ++ show xs ++ ")"
-- These are all fairly useless. Standard constructors and pattern matching work
-- better
{-
nil :: List Unsafe b
nil = Nil
cons :: b -> List a b -> List Safe b
cons = Cons
testnull :: List b a -> (List b Unsafe -> c) -> (List b Safe -> c) -> c
testnull l@(Nil ) is isnot = is l
testnull l@(Cons _ _) is isnot = isnot l
-}
-- For flexibilty, note we don't want the opposite conversion
-- Can't do this one.
-- forget :: List Safe b -> List Unsafe b
-- instead, can only do this one.
data ListUnsafe b = forall a. L (List a b)
-- unL :: ListUnsafe b -> exists a. List a b
-- unL (L l) = l
forget :: List Safe b -> ListUnsafe b
forget = L
instance Show a => Show (ListUnsafe a) where
show (L l) = show l
toList :: List a b -> [b]
toList (Nil ) = []
toList (Cons hd tl) = hd : toList tl
fromList :: [b] -> ListUnsafe b
fromList l = foldr (\x (L xs) -> L (Cons x xs)) (L Nil) l
-- Four operations that require non-empty lists
sHead :: List Safe b -> b
sHead (Cons hd tl) = hd
sTail :: List Safe b -> ListUnsafe b
sTail (Cons hd tl) = L tl
sLast :: List Safe b -> b
-- from prelude
-- last [x] = x
---last (x : xs) = last xs
sLast (Cons x Nil) = x
sLast (Cons x xs@(Cons _ _)) = sLast xs
sInit :: List Safe a -> ListUnsafe a
sInit (Cons x Nil) = L Nil
sInit (Cons x xs@(Cons _ _)) =
-- let (L l) = sInit xs in
-- L (Cons x l)
case (sInit xs) of
L l -> L (Cons x l)
-- Other standard operations that work for any list
sElem :: Eq b => b -> List a b -> Bool
sElem b (Cons x xs) = if b == x then True else sElem b xs
sElem b (Nil) = False
sMap :: (b1 -> b2) -> List a b1 -> List a b2
sMap f (Nil) = Nil
sMap f (Cons x xs) = Cons (f x) (sMap f xs)
sFilter :: (b -> Bool) -> List a b -> ListUnsafe b
sFilter = undefined
sLength :: List a b -> Int
sLength Nil = 0
sLength (Cons x xs) = 1 + sLength xs
-- what is type of (binary) concat??
sConcat :: List a1 b -> List a2 b -> ListUnsafe b
sConcat Nil l = L l
sConcat (Cons x xs) l = case (sConcat xs l) of
L l -> L (Cons x l)