implementation module StrictList

import StdInt, StdMisc, StdBool

:: StrictList a
	= SCons !a (!StrictList a)
	| SNil

instance == (StrictList a) | == a where
  (==) SNil SNil = True
  (==) (SCons x xs) (SCons y ys) = x == y && xs == ys
  (==) _ _ = False

slAppend :: !(StrictList .a) !u:(StrictList .a) -> !u:StrictList .a
slAppend SNil			list` = list`
slAppend (SCons x list)	list` = SCons x (slAppend list list`)

slReverse :: !(StrictList a) -> StrictList a
slReverse list = slReverse` list SNil
  where
	slReverse` (SCons head tail) list = slReverse` tail (SCons head list)
	slReverse` SNil				list = list

slSplitAt :: !Int u:(StrictList .a) -> (StrictList .a, u:StrictList .a)
slSplitAt 0 xs = (SNil, xs)
slSplitAt n (SCons x xs) = (SCons x ys, zs)
  where
	(ys, zs) = slSplitAt (n - 1) xs
slSplitAt _ SNil = (SNil, SNil)

slFromList :: ![a] -> StrictList a
slFromList [] = SNil
slFromList [x:xs] = SCons x (slFromList xs)

slMap :: !(a -> b) !(StrictList a) -> StrictList b
slMap _ SNil = SNil
slMap f (SCons x xs) = SCons (f x) (slMap f xs)

slLength :: !(StrictList a) -> Int
slLength list = slLength` list 0
  where
	slLength` (SCons x xs)	len = slLength` xs (len + 1)
	slLength` SNil			len = len

slHead :: !(StrictList a) -> a
slHead (SCons x xs) = x
slHead SNil = abort "slHead (StrictList.icl): empty list\n"

slTail :: !(StrictList a) -> (StrictList a)
slTail (SCons x xs) = xs
slTail SNil = abort "slTail (StrictList.icl): empty list\n"

slToList :: !(StrictList a) -> [a]
slToList SNil = []
slToList (SCons x xs) = [x:slToList xs]

slIndex :: !Int !(StrictList .a) -> .a
slIndex _ SNil		  
  = abort "slIndex (StrictList.icl): index out of range\n"
slIndex 0 (SCons x _)
  = x
slIndex n (SCons x xs) 
  = slIndex (n - 1) xs

slIsEmpty :: !(StrictList a) -> Bool
slIsEmpty SNil = True
slIsEmpty _	  = False

slTake :: !Int !(StrictList a) -> StrictList a
slTake _  SNil = SNil
slTake 0 list = SNil
slTake nr (SCons x xs) = SCons x (slTake (nr-1) xs)

slDrop :: !Int !(StrictList a) -> StrictList a
slDrop _  SNil  = SNil
slDrop 0  list = list
slDrop nr (SCons x xs) = slDrop (nr-1) xs

slLast :: !(StrictList a) -> a
slLast (SCons lastElement SNil) = lastElement
slLast (SCons x xs)			  = slLast xs

slInit :: !(StrictList a) -> StrictList a
slInit (SCons lastElement SNil)	= SNil
slInit (SCons x xs)				= SCons x (slInit xs)

slUpdate :: !Int !.a !u:(StrictList .a) -> u:StrictList .a
slUpdate _ a SNil			= SCons a SNil
slUpdate 0 a (SCons x xs)	= SCons a xs
slUpdate n a (SCons x xs)	= SCons x (slUpdate (n-1) a xs)
