{-# LANGUAGE GADTs #-} module Data.STRef.Zoom ( STRef , zoomSTRef , newSTRef , pairSTRefs , readSTRef , modifySTRef , modifySTRef' , writeSTRef ) where import Control.Monad.ST import qualified Data.STRef as ST import Control.Lens data STRef s a where Leaf :: ST.STRef s x -> ALens' x a -> STRef s a Branch :: STRef s x -> STRef s y -> ALens' (x,y) a -> STRef s a zoomSTRef :: ALens' a b -> STRef s a -> STRef s b zoomSTRef l1 (Leaf v l2) = Leaf v . fusing $ cloneLens l2 . cloneLens l1 zoomSTRef l1 (Branch x y l2) = Branch x y . fusing $ cloneLens l2 . cloneLens l1 newSTRef :: a -> ST s (STRef s a) newSTRef a = Leaf <$> ST.newSTRef a <*> pure id pairSTRefs :: STRef s a -> STRef s b -> STRef s (a,b) pairSTRefs x y = Branch x y id readSTRef :: STRef s a -> ST s a readSTRef (Leaf v l) = (^#l) <$> ST.readSTRef v readSTRef (Branch x y l) = (^#l) <$> readBranch x y modifySTRef :: STRef s a -> (a -> a) -> ST s () modifySTRef (Leaf v l) f = ST.modifySTRef v $ l #%~ f modifySTRef (Branch x'ref y'ref l) f = do (x,y) <- (l #%~ f) <$> readBranch x'ref y'ref writeSTRef x'ref x writeSTRef y'ref y modifySTRef' :: STRef s a -> (a -> a) -> ST s () modifySTRef' (Leaf v l) f = ST.modifySTRef' v $ l #%~ f modifySTRef' b f = modifySTRef b f writeSTRef :: STRef s a -> a -> ST s () writeSTRef (Leaf v l) a = ST.modifySTRef' v $ l #~ a writeSTRef b a = modifySTRef b $ const a readBranch :: STRef s a -> STRef s b -> ST s (a,b) readBranch x y = (,) <$> readSTRef x <*> readSTRef y