more combinators

This commit is contained in:
Sandy Maguire 2019-02-14 14:47:35 -05:00
parent 0b998cf6f9
commit 537b3cbaad
3 changed files with 40 additions and 23 deletions

View File

@ -4,7 +4,7 @@
{-# LANGUAGE RankNTypes #-} {-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeOperators #-} {-# LANGUAGE TypeOperators #-}
module Eff.Combinators where module Eff.Interpretation where
import qualified Control.Monad.Trans.Except as E import qualified Control.Monad.Trans.Except as E
import Control.Monad.Trans.Cont import Control.Monad.Trans.Cont
@ -35,12 +35,12 @@ interpret f (Freer m) = Freer $ \k -> m $ \u ->
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
-- | Like 'interpret', but with access to intermediate state. -- | Like 'interpret', but with access to intermediate state.
interpretS stateful
:: (eff ~> S.StateT s (Eff r)) :: (eff ~> S.StateT s (Eff r))
-> s -> s
-> Eff (eff ': r) ~> Eff r -> Eff (eff ': r) ~> Eff r
interpretS f s = transform (flip S.evalStateT s) f stateful f s = transform (flip S.evalStateT s) f
{-# INLINE interpretS #-} {-# INLINE stateful #-}
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
@ -48,8 +48,8 @@ interpretS f s = transform (flip S.evalStateT s) f
-- useful for interpreters which would like to introduce some intermediate -- useful for interpreters which would like to introduce some intermediate
-- effects before immediately handling them. -- effects before immediately handling them.
replace replace
:: (eff ~> eff') :: (eff1 ~> eff2)
-> Eff (eff ': r) ~> Eff (eff' ': r) -> Eff (eff1 ': r) ~> Eff (eff2 ': r)
replace = naturally weaken replace = naturally weaken
{-# INLINE replace #-} {-# INLINE replace #-}
@ -80,6 +80,20 @@ shortCircuit
-> Eff (eff ': r) a -> Eff (eff ': r) a
-> Eff r (Either e a) -> Eff r (Either e a)
shortCircuit f = transform E.runExceptT $ \e -> f e shortCircuit f = transform E.runExceptT $ \e -> f e
{-# INLINE shortCircuit #-}
------------------------------------------------------------------------------
-- | Intercept an effect without removing it from the effect stack.
intercept
:: Member eff r
=> (eff ~> Eff r)
-> Eff r ~> Eff r
intercept f (Freer m) = Freer $ \k -> m $ \u ->
case prj u of
Nothing -> k u
Just e -> runIt k $ f e
{-# INLINE intercept #-}
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
@ -116,13 +130,6 @@ naturally z f (Freer m) = Freer $ \k -> m $ \u ->
{-# INLINE naturally #-} {-# INLINE naturally #-}
------------------------------------------------------------------------------
-- | Analogous to MTL's 'lift'.
raise :: Eff r a -> Eff (u ': r) a
raise = hoistEff weaken
{-# INLINE raise #-}
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
-- | Introduce a new effect directly underneath the top of the stack. This is -- | Introduce a new effect directly underneath the top of the stack. This is
-- often useful for interpreters which would like to introduce some intermediate -- often useful for interpreters which would like to introduce some intermediate

View File

@ -58,6 +58,7 @@ liftEff :: f x -> Freer f x
liftEff u = Freer $ \k -> k u liftEff u = Freer $ \k -> k u
{-# INLINE liftEff #-} {-# INLINE liftEff #-}
type f ~> g = forall x. f x -> g x type f ~> g = forall x. f x -> g x
infixr 1 ~> infixr 1 ~>
@ -68,7 +69,7 @@ send t = Freer $ \k -> k $ inj t
runM :: Monad m => Freer (Union '[m]) a -> m a runM :: Monad m => Freer (Union '[m]) a -> m a
runM z = runFreer z extract runM = runIt extract
{-# INLINE runM #-} {-# INLINE runM #-}
@ -79,3 +80,10 @@ run = runIdentity . runM
runIt :: Monad m => (forall t. f t -> m t) -> Freer f a -> m a runIt :: Monad m => (forall t. f t -> m t) -> Freer f a -> m a
runIt k m = runFreer m k runIt k m = runFreer m k
------------------------------------------------------------------------------
-- | Analogous to MTL's 'lift'.
raise :: Eff r a -> Eff (u ': r) a
raise = hoistEff weaken
{-# INLINE raise #-}

View File

@ -12,7 +12,7 @@ module Lib where
import qualified Control.Monad.Trans.Except as E import qualified Control.Monad.Trans.Except as E
import qualified Control.Monad.Trans.State.Strict as S import qualified Control.Monad.Trans.State.Strict as S
import Data.OpenUnion import Data.OpenUnion
import Eff.Combinators import Eff.Interpretation
import Eff.Type import Eff.Type
@ -39,20 +39,18 @@ foom = do
get @String get @String
runTeletype :: forall r a. Member IO r => Eff (State String ': r) a -> Eff r a runTeletype :: Member IO r => Eff (State String ': r) a -> Eff r a
runTeletype = interpret bind runTeletype = interpret $ \case
where Get -> send getLine
bind :: forall x. State String x -> Eff r x Put s -> send $ putStrLn s
bind Get = send getLine
bind (Put s) = send $ putStrLn s
-- main :: IO () -- main :: IO ()
-- main = runM (runState "fuck" foom) >>= print -- main = runM (runState "fuck" foom) >>= print
runState :: forall s r a. s -> Eff (State s ': r) a -> Eff r a runState :: s -> Eff (State s ': r) a -> Eff r a
runState = interpretS $ \case runState = stateful $ \case
Get -> S.get Get -> S.get
Put s' -> S.put s' Put s' -> S.put s'
@ -73,3 +71,7 @@ runError = shortCircuit $ \(Error e) -> E.throwE e
runErrorRelay :: Eff (Error e ': r) a -> Eff r (Either e a) runErrorRelay :: Eff (Error e ': r) a -> Eff r (Either e a)
runErrorRelay = relay (pure . Right) $ \(Error e) _ -> pure $ Left e runErrorRelay = relay (pure . Right) $ \(Error e) _ -> pure $ Left e
subsume :: Member eff r => Eff (eff ': r) ~> Eff r
subsume = interpret send