module Control.Monad.ExtRef.Pure
( runExtRef
, runExtRef_
) where
import Control.Monad.Base
import Control.Monad.Trans.Control
import Control.Monad.State
import Control.Monad.Reader
import Control.Monad.Identity
import Control.Category
import Control.Arrow ((***))
import Data.Sequence
import Data.Lens.Common
import Data.Foldable (toList)
import Prelude hiding ((.), id, splitAt, length)
import Unsafe.Coerce
import System.IO.Unsafe
import Control.Monad.Restricted
import Control.Monad.ExtRef
newtype Lens_ a b = Lens_ {unLens_ :: Lens' a b}
instance Reference (Lens_ a) where
type RefMonad (Lens_ a) = State a
readRef (Lens_ r) = reader $ getL r
writeRef (Lens_ r) = modify . setL r
lensMap l (Lens_ r) = Lens_ $ r . l
unitRef = Lens_ $ lens (const ()) (flip $ const id)
joinRef m = (\f -> Lens_ $ \g s -> unLens_ (f s) g s) $ runReader m
type LSt = Seq CC
initLSt :: LSt
initLSt = empty
data CC = forall a . CC (LSt -> a -> a) a
ap_ :: LSt -> CC -> CC
ap_ x (CC f a) = CC f (f x a)
unsafeData :: CC -> a
unsafeData (CC _ a) = unsafeCoerce a
instance Monad m => ExtRef (StateT LSt m) where
type Ref (StateT LSt m) = Lens_ LSt
liftWriteRef = mapStateT (return . runIdentity)
extRef (Lens_ r1) r2 a0 = state extend where
rk = setL r1 . getL r2
kr = setL r2 . getL r1
extend x0 = (Lens_ $ lens get set, x0 |> CC kr (kr x0 a0))
where
limit = (id *** toList) . splitAt (length x0)
get = unsafeData . head . snd . limit
set x a = foldl (\x -> (|>) x . ap_ x) (rk a zs |> CC kr a) ys where
(zs, _ : ys) = limit x
instance (ExtRef n, Monad m) => ExtRef (Ext n m) where
type Ref (Ext n m) = Ref n
liftWriteRef = lift' . liftWriteRef
extRef r1 r2 = lift' . extRef r1 r2
runExtRef :: Monad m => (forall t . (MonadTrans t, ExtRef (t m)) => t m a) -> m a
runExtRef s = evalStateT s initLSt
instance SafeIO (Reader (Seq CC)) where
getArgs = runSafeIO getArgs
getProgName = runSafeIO getProgName
lookupEnv = runSafeIO . lookupEnv
runSafeIO :: Monad m => IO a -> m a
runSafeIO = return . unsafePerformIO
runExtRef_
:: forall m a . (MonadBase m m, NewRef m)
=> (forall t . (MonadTrans t, ExtRef (t m), NewRef (t m), MonadIO (t IO), MonadBaseControl IO (t IO), SafeIO (ReadRef (t IO)), SafeIO (t IO)) => t m a)
-> m a
runExtRef_ f = newRef' initLSt >>= flip runExt f