{-# LANGUAGE ExistentialQuantification #-}
module Data.IOVar (IOVar,newIOVar,readIOVar,writeIOVar) where

import Definitive
import Data.IORef

data IOVar w r = IOVar (IORef w) (w -> IO r)

undefRef :: IORef a
undefRef = newIORef undefined ^. thunk

instance Functor (IOVar w) where
  map f (IOVar r g) = IOVar r (map f . g)
instance Unit (IOVar w) where
  pure a = IOVar undefRef (const (pure a))
instance SemiApplicative (IOVar w)
instance Applicative (IOVar w)
instance Monad (IOVar w) where
  join (IOVar r f) = IOVar r (f >=> \(IOVar r' f') -> readIORef r' >>= f')

newIOVar :: a -> IO (IOVar a a)
newIOVar a = newIORef a <&> \r -> IOVar r pure
readIOVar :: IOVar w r -> IO r
readIOVar (IOVar ref k) = readIORef ref >>= k
writeIOVar :: IOVar w r -> w -> IO ()
writeIOVar (IOVar ref _) w = writeIORef ref w