{-# LANGUAGE ScopedTypeVariables #-}
module Data.Extensible.Tangle
( TangleT(..)
, lasso
, hitchAt
, runTangleT
, evalTangleT
, runTangles
) where
import Control.Applicative
import Control.Monad.Trans.RWS.Strict
import Control.Monad.Trans.Class
import Data.Extensible.Class
import Data.Extensible.Field
import Data.Extensible.Product
import Data.Extensible.Internal.Rig
import Data.Extensible.Nullable
import Data.Extensible.Wrapper
newtype TangleT xs h m a = TangleT
{ unTangleT :: RWST (xs :& Comp (TangleT xs h m) h) () (xs :& Nullable h) m a }
deriving (Functor, Applicative, Monad)
instance MonadTrans (TangleT xs h) where
lift = TangleT . lift
instance (Monad m, Semigroup a) => Semigroup (TangleT xs h m a) where
(<>) = liftA2 (<>)
instance (Monad m, Monoid a) => Monoid (TangleT xs h m a) where
mempty = pure mempty
mappend = (<>)
lasso :: forall k v m h xs. (Monad m, Lookup xs k v, Wrapper h)
=> FieldName k -> TangleT xs h m (Repr h (k ':> v))
lasso _ = view _Wrapper <$> hitchAt (association :: Membership xs (k ':> v))
{-# INLINE lasso #-}
hitchAt :: Monad m => Membership xs x -> TangleT xs h m (h x)
hitchAt k = TangleT $ do
mem <- get
case getNullable $ hlookup k mem of
Just a -> return a
Nothing -> do
tangles <- ask
a <- unTangleT $ getComp $ hlookup k tangles
modify $ over (pieceAt k) $ const $ Nullable $ Just a
return a
runTangleT :: Monad m
=> xs :& Comp (TangleT xs h m) h
-> xs :& Nullable h
-> TangleT xs h m a
-> m (a, xs :& Nullable h)
runTangleT tangles rec0 (TangleT m) = (\(a, s, _) -> (a, s))
<$> runRWST m tangles rec0
{-# INLINE runTangleT #-}
evalTangleT :: Monad m
=> xs :& Comp (TangleT xs h m) h
-> xs :& Nullable h
-> TangleT xs h m a
-> m a
evalTangleT tangles rec0 (TangleT m) = fst <$> evalRWST m tangles rec0
{-# INLINE evalTangleT #-}
runTangles :: Monad m
=> xs :& Comp (TangleT xs h m) h
-> xs :& Nullable h
-> m (xs :& h)
runTangles ts vs = evalTangleT ts vs $ htraverseWithIndex (const . hitchAt) vs
{-# INLINE runTangles #-}