From 9db210f5109e8ad3c119224a0cd78d8b0ff4d104 Mon Sep 17 00:00:00 2001 From: Tom Ellis Date: Sun, 8 Sep 2024 18:11:17 +0100 Subject: [PATCH] Some docs --- .../src/Bluefin/Internal/Effectful.hs | 168 +++++++++++------- 1 file changed, 102 insertions(+), 66 deletions(-) diff --git a/bluefin-internal/src/Bluefin/Internal/Effectful.hs b/bluefin-internal/src/Bluefin/Internal/Effectful.hs index 20a7bc3..b46d244 100644 --- a/bluefin-internal/src/Bluefin/Internal/Effectful.hs +++ b/bluefin-internal/src/Bluefin/Internal/Effectful.hs @@ -12,66 +12,28 @@ import Effectful.Internal.Env import qualified Effectful.Internal.Monad as Effectful import qualified Effectful.State.Dynamic as St -newtype Effectful es (e :: Effects) = MkEffectful (Env es) +-- * Bluefin handle -data Bluefin es m a +-- | Provide access to Effectful operations in Bluefin +newtype Effectful (es' :: [EffectfulEffect]) (e :: Effects) + = MkEffectful (Env es') -type instance DispatchOf (Bluefin es) = Dynamic +-- * Effectful effect -voidBluefin :: Bluefin es m a -> r -voidBluefin = \case {} +-- | Provide access to Bluefin operations in Effectful +data Bluefin es m a -useEffectful :: - (e :> es) => - -- | Bluefin handle to @effectful@ operations - Effectful effes e -> - -- | An @effectful@ operation - Effectful.Eff effes r -> - Eff es r -useEffectful e k = - fromEffectful (\Proxy -> Effectful.inject k) e +-- * Type synonyms -useBluefin :: - forall es effes r. - (Bluefin es Effectful.:> effes) => - Eff es r -> - Effectful.Eff effes r -useBluefin m = - toEffectful (\(_ :: Effectful effes e) -> useImpl @es @(e :& es) m) +type instance DispatchOf (Bluefin es) = Dynamic -toEffectful :: - forall es effes a. - (Bluefin es Effectful.:> effes) => - (forall e. Effectful effes e -> Eff (e :& es) a) -> - Effectful.Eff effes a -toEffectful = unsafeToEffectful +type EffectfulEff = Effectful.Eff -unsafeInterpretBluefin :: - Effectful.Eff (Bluefin es : effes) a -> Effectful.Eff effes a -unsafeInterpretBluefin = Effectful.interpret (\_ -> voidBluefin) +type EffectfulEffect = Effectful.Effect -fromEffectful :: - (e :> es) => - (Proxy es -> Effectful.Eff (Bluefin es : effes) r) -> - Effectful effes e -> - Eff es r -fromEffectful m (MkEffectful env) = - UnsafeMkEff (Effectful.unEff (unsafeInterpretBluefin (m Proxy)) env) +type a ::> b = a Effectful.:> b -unsafeToEffectful :: (Effectful es e -> Eff es' a) -> Effectful.Eff es a -unsafeToEffectful m = - Effectful.unsafeEff (\env' -> unsafeUnEff (m (MkEffectful env'))) - -handleWith :: - (e1 :> es) => - -- | An @effectful@ handler - (Effectful.Eff (effe : effes) r1 -> Effectful.Eff effes r2) -> - -- | An @effectful@ operation, in Bluefin style - (forall e. Effectful (effe : effes) e -> Eff (e :& es) r1) -> - Effectful effes e1 -> - Eff es r2 -handleWith handler m (MkEffectful env) = - UnsafeMkEff (Effectful.unEff (handler (unsafeToEffectful m)) env) +-- * Bluefin handlers runEffectful :: (e1 :> es) => @@ -87,26 +49,86 @@ runPureEffectful :: Eff es r runPureEffectful k = pure (Effectful.runPureEff (unsafeToEffectful k)) +handleWith :: + (e1 :> es) => + -- | An @effectful@ handler + (EffectfulEff (e' : es') r1 -> EffectfulEff es' r2) -> + -- | An @effectful@ operation, in Bluefin style + (forall e. Effectful (e' : es') e -> Eff (e :& es) r1) -> + Effectful es' e1 -> + -- | The result of handling the @effectful@ operation in Bluefin + -- style using the @effectful@ handler + Eff es r2 +handleWith handler m (MkEffectful env) = + UnsafeMkEff (Effectful.unEff (handler (unsafeToEffectful m)) env) + +-- * Effectful handlers + runBluefin :: - Effectful.IOE Effectful.:> effes => - (forall e es. IOE e -> Effectful.Eff (Bluefin (e :& es) : effes) r) -> - Effectful.Eff effes r + (Effectful.IOE ::> es') => + -- | A Bluefin operation, in Effectful style (with IO) + (forall e es. IOE e -> EffectfulEff (Bluefin (e :& es) : es') r) -> + EffectfulEff es' r runBluefin m = unsafeInterpretBluefin (m MkIOE) runPureBluefin :: - (forall es. Effectful.Eff (Bluefin es : effes) r) -> - Effectful.Eff effes r + -- | A Bluefin operation, in Effectful style (without IO) + (forall es. EffectfulEff (Bluefin es : es') r) -> + EffectfulEff es' r runPureBluefin = unsafeInterpretBluefin +-- * Use Bluefin operations in @effectful@ and vice versa + +useEffectful :: + (e :> es) => + -- | Bluefin handle to @effectful@ operations + Effectful es' e -> + -- | An @effectful@ operation + EffectfulEff es' r -> + Eff es r +useEffectful e k = + fromEffectful (\Proxy -> Effectful.inject k) e + +useBluefin :: + forall es es' r. + (Bluefin es ::> es') => + Eff es r -> + -- | ͘ + EffectfulEff es' r +useBluefin m = + toEffectful (\(_ :: Effectful es' e) -> useImpl @es @(e :& es) m) + +-- * Conversion between @effectful@ and Bluefin + +toEffectful :: + forall (es :: Effects) (es' :: [EffectfulEffect]) a. + (Bluefin es ::> es') => + (forall e. Effectful es' e -> Eff (e :& es) a) -> + -- | ͘ + EffectfulEff es' a +toEffectful = unsafeToEffectful + +fromEffectful :: + (e :> es) => + (Proxy es -> EffectfulEff (Bluefin es : es') r) -> + Effectful es' e -> + -- | ͘ + Eff es r +fromEffectful m (MkEffectful env) = + UnsafeMkEff (Effectful.unEff (unsafeInterpretBluefin (m Proxy)) env) + +-- * Example code + example :: - ( St.State Int Effectful.:> es, - Er.Error String Effectful.:> es, - Bluefin bes Effectful.:> es, - e :> bes + ( St.State Int ::> es', + Er.Error String ::> es', + Bluefin es ::> es', + e :> es ) => State Int e -> - Proxy bes -> - Effectful.Eff es Int + Proxy es -> + -- | ͘ + EffectfulEff es' Int example bst (_ :: Proxy bes) = do r <- St.get St.put (r + 1 :: Int) @@ -116,14 +138,15 @@ example bst (_ :: Proxy bes) = do St.get bfExample :: - forall e es e1 effes. + forall e es e1 es'. ( e :> es, e1 :> es, - St.State Int Effectful.:> effes, - Er.Error String Effectful.:> effes + St.State Int ::> es', + Er.Error String ::> es' ) => State Int e1 -> - Effectful effes e -> + Effectful es' e -> + -- | ͘ Eff es Int bfExample s e = do r <- fromEffectful (\_ -> example s (Proxy @es)) e @@ -146,3 +169,16 @@ runExample i = -- Right 10 -- > runExample 10 -- Left "foo" + +-- * Unsafe internals + +voidBluefin :: Bluefin es m a -> r +voidBluefin = \case {} + +unsafeInterpretBluefin :: + EffectfulEff (Bluefin es : es') a -> EffectfulEff es' a +unsafeInterpretBluefin = Effectful.interpret (\_ -> voidBluefin) + +unsafeToEffectful :: (Effectful es e -> Eff es' a) -> EffectfulEff es a +unsafeToEffectful m = + Effectful.unsafeEff (\env' -> unsafeUnEff (m (MkEffectful env')))