snap-1.1.2.0: src/Snap/Snaplet/Internal/Lensed.hs
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
module Snap.Snaplet.Internal.Lensed where
------------------------------------------------------------------------------
import Control.Applicative (Alternative (..),
Applicative (..), (<$>))
import Control.Category ((.))
import Control.Lens (ALens', cloneLens, storing, (^#))
import Control.Monad (MonadPlus (..), liftM)
import Control.Monad.Base (MonadBase (..))
import qualified Control.Monad.Fail as Fail
import Control.Monad.Reader (MonadReader (..))
import Control.Monad.State.Class (MonadState (..))
import Control.Monad.Trans (MonadIO (..), MonadTrans (..))
import Control.Monad.Trans.Control (ComposeSt, MonadBaseControl (..),
MonadTransControl (..),
defaultLiftBaseWith,
defaultRestoreM)
import Control.Monad.Trans.State (StateT(..))
import Prelude (Functor (..), Monad (..), ($))
import Snap.Core (MonadSnap (..))
------------------------------------------------------------------------------
------------------------------------------------------------------------------
newtype Lensed b v m a = Lensed
{ unlensed :: ALens' b v -> v -> b -> m (a, v, b) }
------------------------------------------------------------------------------
instance Functor m => Functor (Lensed b v m) where
fmap f (Lensed g) = Lensed $ \l v s ->
(\(a,v',s') -> (f a, v', s')) <$> g l v s
------------------------------------------------------------------------------
instance (Functor m, Monad m) => Applicative (Lensed b v m) where
pure a = Lensed $ \_ v s -> return (a, v, s)
Lensed mf <*> Lensed ma = Lensed $ \l v s -> do
(f, v', s') <- mf l v s
(\(a,v'',s'') -> (f a, v'', s'')) <$> ma l v' s'
------------------------------------------------------------------------------
instance Fail.MonadFail m => Fail.MonadFail (Lensed b v m) where
fail s = Lensed $ \_ _ _ -> Fail.fail s
------------------------------------------------------------------------------
instance Monad m => Monad (Lensed b v m) where
return a = Lensed $ \_ v s -> return (a, v, s)
Lensed g >>= k = Lensed $ \l v s -> do
(a, v', s') <- g l v s
unlensed (k a) l v' s'
------------------------------------------------------------------------------
instance Monad m => MonadState v (Lensed b v m) where
get = Lensed $ \_ v s -> return (v, v, s)
put v' = Lensed $ \_ _ s -> return ((), v', s)
instance Monad m => MonadReader (ALens' b v) (Lensed b v m) where
ask = Lensed $ \l v s -> return (l, v, s)
local = lensedLocal
------------------------------------------------------------------------------
lensedLocal :: Monad m => (ALens' b v -> ALens' b v') -> Lensed b v' m a -> Lensed b v m a
lensedLocal f g = do
l <- ask
withTop (f l) g
------------------------------------------------------------------------------
instance MonadTrans (Lensed b v) where
lift m = Lensed $ \_ v b -> do
res <- m
return (res, v, b)
------------------------------------------------------------------------------
instance MonadIO m => MonadIO (Lensed b v m) where
liftIO = lift . liftIO
------------------------------------------------------------------------------
instance MonadPlus m => MonadPlus (Lensed b v m) where
mzero = lift mzero
m `mplus` n = Lensed $ \l v b ->
unlensed m l v b `mplus` unlensed n l v b
------------------------------------------------------------------------------
instance (Monad m, Alternative m) => Alternative (Lensed b v m) where
empty = lift empty
Lensed m <|> Lensed n = Lensed $ \l v b -> m l v b <|> n l v b
------------------------------------------------------------------------------
instance MonadSnap m => MonadSnap (Lensed b v m) where
liftSnap = lift . liftSnap
------------------------------------------------------------------------------
instance MonadBase base m => MonadBase base (Lensed b v m) where
liftBase = lift . liftBase
------------------------------------------------------------------------------
instance MonadBaseControl base m => MonadBaseControl base (Lensed b v m) where
type StM (Lensed b v m) a = ComposeSt (Lensed b v) m a
liftBaseWith = defaultLiftBaseWith
restoreM = defaultRestoreM
{-# INLINE liftBaseWith #-}
{-# INLINE restoreM #-}
------------------------------------------------------------------------------
instance MonadTransControl (Lensed b v) where
type StT (Lensed b v) a = (a, v, b)
liftWith f = Lensed $ \l v b -> do
res <- f $ \(Lensed g) -> g l v b
return (res, v, b)
restoreT k = Lensed $ \_ _ _ -> k
{-# INLINE liftWith #-}
{-# INLINE restoreT #-}
------------------------------------------------------------------------------
globally :: Monad m => StateT b m a -> Lensed b v m a
globally (StateT f) = Lensed $ \l v s ->
liftM (\(a, s') -> (a, s' ^# l, s')) $ f (storing l v s)
------------------------------------------------------------------------------
lensedAsState :: Monad m => Lensed b v m a -> ALens' b v -> StateT b m a
lensedAsState (Lensed f) l = StateT $ \s -> do
(a, v', s') <- f l (s ^# l) s
return (a, storing l v' s')
------------------------------------------------------------------------------
getBase :: Monad m => Lensed b v m b
getBase = Lensed $ \_ v b -> return (b, v, b)
------------------------------------------------------------------------------
withTop :: Monad m => ALens' b v' -> Lensed b v' m a -> Lensed b v m a
withTop l m = globally $ lensedAsState m l
------------------------------------------------------------------------------
with :: Monad m => ALens' v v' -> Lensed b v' m a -> Lensed b v m a
with l g = do
l' <- ask
withTop (cloneLens l' . l) g
------------------------------------------------------------------------------
embed :: Monad m => ALens' v v' -> Lensed v v' m a -> Lensed b v m a
embed l m = locally $ lensedAsState m l
------------------------------------------------------------------------------
locally :: Monad m => StateT v m a -> Lensed b v m a
locally (StateT f) = Lensed $ \_ v s ->
liftM (\(a, v') -> (a, v', s)) $ f v
------------------------------------------------------------------------------
runLensed :: Monad m
=> Lensed t1 b m t
-> ALens' t1 b
-> t1
-> m (t, t1)
runLensed (Lensed f) l s = do
(a, v', s') <- f l (s ^# l) s
return (a, storing l v' s')