Skip to content

Instantly share code, notes, and snippets.

@evgenii-malov
Created September 5, 2022 05:53
Show Gist options
  • Save evgenii-malov/812e1b2305dcf969ee6b22ced1fcaed2 to your computer and use it in GitHub Desktop.
Save evgenii-malov/812e1b2305dcf969ee6b22ced1fcaed2 to your computer and use it in GitHub Desktop.
Haskell linked list with ST monad
-- see video https://www.youtube.com/watch?v=MJscn-m4KIo&t=3943s
import Data.STRef
import Control.Monad.ST
import Data.Maybe
import Control.Monad
import Data.Either (fromRight, isLeft, fromLeft)
import Debug.Trace
data Llist s a = Llist {llen:: STRef s Int, lhead:: STRef s (Maybe (Node s a)) }
data Node s a = Node {val:: STRef s a, next:: STRef s (Maybe (Node s a))}
empty :: ST s (Llist s a)
empty = Llist <$> newSTRef 0 <*> newSTRef Nothing
prepend :: a -> Llist s a -> ST s ()
prepend v (Llist c nr) = do
old <- readSTRef nr
nr' <- newSTRef old
vr <- newSTRef v
modifySTRef c (+1)
writeSTRef nr (Just $ Node vr nr')
toList :: ST s (Llist s a) -> ST s [a]
toList sl = do
(Llist cr nr) <- sl
c <- readSTRef cr
nr' <- readSTRef nr
if c == 0 then return [] else go $ fromJust nr'
where
go :: Node s a -> ST s [a]
go (Node vr nr) = do
v <- readSTRef vr
n <- readSTRef nr
if isNothing n then return [v] else (v:) <$> go (fromJust n)
get_ :: Llist s a -> Int -> ST s (Either String (Node s a))
get_ l i | i<0 = return $ Left "Negative index"
| otherwise = do
c <- readSTRef $ llen l
nr <- readSTRef $ lhead l
if i>=c then return $ Left "To big index" else go (fromJust nr) i
where
go n 0 = return $ Right n
go n i = do nn <- readSTRef $ next n
go (fromJust nn) (i-1)
get :: Llist s a -> Int -> ST s a
get l i = do
r <- get_ l i
if isLeft r then error $ fromLeft undefined r else readSTRef $ val $ fromRight undefined r
insert :: Llist s a -> Int -> a -> ST s ()
insert l 0 v = prepend v l
insert l@(Llist c _) i v = do
when (i<0) $ return $! error "index less then 0"
size <- readSTRef c
when (i>size) $ return $! error "to big index"
(Right (Node _ nr)) <- get_ l (i-1)
nn <- get_ l i
nrp <- newSTRef $ if i < size then Just $ fromRight undefined nn else Nothing
vr <- newSTRef v
writeSTRef nr $ Just $ Node vr nrp
modifySTRef c (+1)
insertAfter :: Node s a -> a -> ST s ()
insertAfter = undefined
delete :: Llist s a -> Int -> ST s ()
delete l i = do
size <- readSTRef $ llen l
when (i<0) $ return $! error "index is negative"
when (size == 0) $ return $! error "List is empty"
when (i>=size) $ return $! error "To big index"
if i == 0
then do
(Just (Node _ r)) <- readSTRef $ lhead l
nn <- readSTRef r
writeSTRef (lhead l) nn
else do
(Right (Node _ nr)) <- get_ l i
nv' <- readSTRef nr
(Right (Node _ n)) <- get_ l $ i-1
writeSTRef n nv'
modifySTRef (llen l) (flip (-) 1)
update :: Llist s a -> Int -> a -> ST s ()
update l i v = do
delete l i
insert l i v
b :: ST s (Llist s Integer)
b = do
l <- empty
prepend 1 l
prepend 2 l
prepend 3 l
prepend 4 l
v <- get l 2
traceM $ show v
insert l 4 7
--delete l (-1)
update l (4) 100
return l
@evgenii-malov
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment