packages feed

polysemy 0.5.1.0 → 0.6.0.0

raw patch · 21 files changed

+349/−367 lines, 21 filesdep +loopbreakerdep +type-errorsPVP ok

version bump matches the API change (PVP)

Dependencies added: loopbreaker, type-errors

API changes (from Hackage documentation)

- Polysemy.Internal.Forklift: runViaForklift_b :: LastMember (Lift IO) r => InChan (Forklift r) -> Sem r a -> Sem '[Lift IO] a
+ Polysemy.IO: runEmbedded :: (LastMember (Lift IO) r, MonadIO m) => (forall x. m x -> IO x) -> Sem (Lift m : r) a -> Sem r a
+ Polysemy.Internal.CustomErrors: type AmbiguousSend r e = (IfStuck r (AmbiguousSendError 'TyVarR r e) (Pure (AmbiguousSendError (UnstuckRState r) r e)))
+ Polysemy.Internal.CustomErrors: type WhenStuck expr b = IfStuck expr b NoErrorFcf
+ Polysemy.Internal.CustomErrors.Redefined: data AnythingOfAnyKind
+ Polysemy.Internal.CustomErrors.Redefined: type UnlessStuck expr c = IfStuck expr NoError c
+ Polysemy.Internal.CustomErrors.Redefined: type WhenStuck expr b = IfStuck expr b NoErrorFcf
+ Polysemy.Internal.CustomErrors.Redefined: type family IfStuck (expr :: k) (b :: k1) (c :: Exp k1) :: k1
+ Polysemy.Internal.Union: type MemberWithError e r = (MemberNoError e r, WhenStuck (IndexOf r (Found r e)) (AmbiguousSend r e))
+ Polysemy.Output: runOutputAsList :: forall o r a. Sem (Output o : r) a -> Sem r ([o], a)
- Polysemy: intercept :: (Member e r, FirstOrder m0 e "intercept") => (forall x m. e m x -> Sem r x) -> Sem r a -> Sem r a
+ Polysemy: intercept :: (Member e r, FirstOrder e "intercept") => (forall x m. e m x -> Sem r x) -> Sem r a -> Sem r a
- Polysemy: interpret :: FirstOrder m0 e "interpret" => (forall x m. e m x -> Sem r x) -> Sem (e : r) a -> Sem r a
+ Polysemy: interpret :: FirstOrder e "interpret" => (forall x m. e m x -> Sem r x) -> Sem (e : r) a -> Sem r a
- Polysemy: reinterpret :: forall e1 e2 m0 r a. FirstOrder m0 e1 "reinterpret" => (forall m x. e1 m x -> Sem (e2 : r) x) -> Sem (e1 : r) a -> Sem (e2 : r) a
+ Polysemy: reinterpret :: forall e1 e2 r a. FirstOrder e1 "reinterpret" => (forall m x. e1 m x -> Sem (e2 : r) x) -> Sem (e1 : r) a -> Sem (e2 : r) a
- Polysemy: reinterpret2 :: forall e1 e2 e3 m0 r a. FirstOrder m0 e1 "reinterpret2" => (forall m x. e1 m x -> Sem (e2 : (e3 : r)) x) -> Sem (e1 : r) a -> Sem (e2 : (e3 : r)) a
+ Polysemy: reinterpret2 :: forall e1 e2 e3 r a. FirstOrder e1 "reinterpret2" => (forall m x. e1 m x -> Sem (e2 : (e3 : r)) x) -> Sem (e1 : r) a -> Sem (e2 : (e3 : r)) a
- Polysemy: reinterpret3 :: forall e1 e2 e3 e4 m0 r a. FirstOrder m0 e1 "reinterpret3" => (forall m x. e1 m x -> Sem (e2 : (e3 : (e4 : r))) x) -> Sem (e1 : r) a -> Sem (e2 : (e3 : (e4 : r))) a
+ Polysemy: reinterpret3 :: forall e1 e2 e3 e4 r a. FirstOrder e1 "reinterpret3" => (forall m x. e1 m x -> Sem (e2 : (e3 : (e4 : r))) x) -> Sem (e1 : r) a -> Sem (e2 : (e3 : (e4 : r))) a
- Polysemy: type Member e r = Member' e r
+ Polysemy: type Member e r = MemberNoError e r
- Polysemy.Async: async :: forall r_aw6y a_avYs. Member Async r_aw6y => Sem r_aw6y a_avYs -> Sem r_aw6y (Async (Maybe a_avYs))
+ Polysemy.Async: async :: forall r_au5T a_atXN. MemberWithError Async r_au5T => Sem r_au5T a_atXN -> Sem r_au5T (Async (Maybe a_atXN))
- Polysemy.Async: await :: forall r_aw6A a_avXj. Member Async r_aw6A => Async a_avXj -> Sem r_aw6A a_avXj
+ Polysemy.Async: await :: forall r_au5V a_atWE. MemberWithError Async r_au5V => Async a_atWE -> Sem r_au5V a_atWE
- Polysemy.Error: catch :: forall e_atKA r_atMC a_atKC. Member (Error e_atKA) r_atMC => Sem r_atMC a_atKC -> (e_atKA -> Sem r_atMC a_atKC) -> Sem r_atMC a_atKC
+ Polysemy.Error: catch :: forall e_asba r_asdc a_asbc. MemberWithError (Error e_asba) r_asdc => Sem r_asdc a_asbc -> (e_asba -> Sem r_asdc a_asbc) -> Sem r_asdc a_asbc
- Polysemy.Error: throw :: forall e_atKA r_atMA a_atKC. Member (Error e_atKA) r_atMA => e_atKA -> Sem r_atMA a_atKC
+ Polysemy.Error: throw :: forall e_asba r_asda a_asbc. MemberWithError (Error e_asba) r_asda => e_asba -> Sem r_asda a_asbc
- Polysemy.Input: input :: forall a_aAVo r_aAWi. Member (Input a_aAVo) r_aAWi => Sem r_aAWi a_aAVo
+ Polysemy.Input: input :: forall a_ayPD r_ayQx. MemberWithError (Input a_ayPD) r_ayQx => Sem r_ayQx a_ayPD
- Polysemy.Internal: type Member e r = Member' e r
+ Polysemy.Internal: type Member e r = MemberNoError e r
- Polysemy.Internal.Combinators: intercept :: (Member e r, FirstOrder m0 e "intercept") => (forall x m. e m x -> Sem r x) -> Sem r a -> Sem r a
+ Polysemy.Internal.Combinators: intercept :: (Member e r, FirstOrder e "intercept") => (forall x m. e m x -> Sem r x) -> Sem r a -> Sem r a
- Polysemy.Internal.Combinators: interpret :: FirstOrder m0 e "interpret" => (forall x m. e m x -> Sem r x) -> Sem (e : r) a -> Sem r a
+ Polysemy.Internal.Combinators: interpret :: FirstOrder e "interpret" => (forall x m. e m x -> Sem r x) -> Sem (e : r) a -> Sem r a
- Polysemy.Internal.Combinators: reinterpret :: forall e1 e2 m0 r a. FirstOrder m0 e1 "reinterpret" => (forall m x. e1 m x -> Sem (e2 : r) x) -> Sem (e1 : r) a -> Sem (e2 : r) a
+ Polysemy.Internal.Combinators: reinterpret :: forall e1 e2 r a. FirstOrder e1 "reinterpret" => (forall m x. e1 m x -> Sem (e2 : r) x) -> Sem (e1 : r) a -> Sem (e2 : r) a
- Polysemy.Internal.Combinators: reinterpret2 :: forall e1 e2 e3 m0 r a. FirstOrder m0 e1 "reinterpret2" => (forall m x. e1 m x -> Sem (e2 : (e3 : r)) x) -> Sem (e1 : r) a -> Sem (e2 : (e3 : r)) a
+ Polysemy.Internal.Combinators: reinterpret2 :: forall e1 e2 e3 r a. FirstOrder e1 "reinterpret2" => (forall m x. e1 m x -> Sem (e2 : (e3 : r)) x) -> Sem (e1 : r) a -> Sem (e2 : (e3 : r)) a
- Polysemy.Internal.Combinators: reinterpret3 :: forall e1 e2 e3 e4 m0 r a. FirstOrder m0 e1 "reinterpret3" => (forall m x. e1 m x -> Sem (e2 : (e3 : (e4 : r))) x) -> Sem (e1 : r) a -> Sem (e2 : (e3 : (e4 : r))) a
+ Polysemy.Internal.Combinators: reinterpret3 :: forall e1 e2 e3 e4 r a. FirstOrder e1 "reinterpret3" => (forall m x. e1 m x -> Sem (e2 : (e3 : (e4 : r))) x) -> Sem (e1 : r) a -> Sem (e2 : (e3 : (e4 : r))) a
- Polysemy.Internal.CustomErrors: type FirstOrder m e fn = IfStuck e (() :: Constraint) (FirstOrderFcf m e fn)
+ Polysemy.Internal.CustomErrors: type FirstOrder (e :: Effect) fn = UnlessStuck e (FirstOrderErrorFcf e fn)
- Polysemy.Internal.Union: type Member e r = Member' e r
+ Polysemy.Internal.Union: type Member e r = MemberNoError e r
- Polysemy.Output: output :: forall o_aAgk r_aAhd. Member (Output o_aAgk) r_aAhd => o_aAgk -> Sem r_aAhd ()
+ Polysemy.Output: output :: forall o_ay5t r_ay6m. MemberWithError (Output o_ay5t) r_ay6m => o_ay5t -> Sem r_ay6m ()
- Polysemy.Output: runBatchOutput :: forall o r a. Int -> Sem (Output [o] : r) a -> Sem (Output [[o]] : r) a
+ Polysemy.Output: runBatchOutput :: forall o r a. Int -> Sem (Output o : r) a -> Sem (Output [o] : r) a
- Polysemy.Reader: ask :: forall a_aBhw r_aBj4. Member (Reader a_aBhw) r_aBj4 => Sem r_aBj4 a_aBhw
+ Polysemy.Reader: ask :: forall a_azcn r_azdV. MemberWithError (Reader a_azcn) r_azdV => Sem r_azdV a_azcn
- Polysemy.Reader: local :: forall i_aBhu r_aBj5 a_aBhw. Member (Reader i_aBhu) r_aBj5 => (i_aBhu -> i_aBhu) -> Sem r_aBj5 a_aBhw -> Sem r_aBj5 a_aBhw
+ Polysemy.Reader: local :: forall i_azcl r_azdW a_azcn. MemberWithError (Reader i_azcl) r_azdW => (i_azcl -> i_azcl) -> Sem r_azdW a_azcn -> Sem r_azdW a_azcn
- Polysemy.Resource: bracket :: forall r_axDA a_axDk c_axDl a_axBk. Member Resource r_axDA => Sem r_axDA a_axDk -> (a_axDk -> Sem r_axDA c_axDl) -> (a_axDk -> Sem r_axDA a_axBk) -> Sem r_axDA a_axBk
+ Polysemy.Resource: bracket :: forall r_avy6 a_avxQ c_avxR a_avvQ. MemberWithError Resource r_avy6 => Sem r_avy6 a_avxQ -> (a_avxQ -> Sem r_avy6 c_avxR) -> (a_avxQ -> Sem r_avy6 a_avvQ) -> Sem r_avy6 a_avvQ
- Polysemy.Resource: bracketOnError :: forall r_axDE a_axDs c_axDt a_axBk. Member Resource r_axDE => Sem r_axDE a_axDs -> (a_axDs -> Sem r_axDE c_axDt) -> (a_axDs -> Sem r_axDE a_axBk) -> Sem r_axDE a_axBk
+ Polysemy.Resource: bracketOnError :: forall r_avya a_avxY c_avxZ a_avvQ. MemberWithError Resource r_avya => Sem r_avya a_avxY -> (a_avxY -> Sem r_avya c_avxZ) -> (a_avxY -> Sem r_avya a_avvQ) -> Sem r_avya a_avvQ
- Polysemy.State: get :: forall a_az9v r_azaZ. Member (State a_az9v) r_azaZ => Sem r_azaZ a_az9v
+ Polysemy.State: get :: forall a_awY0 r_awZu. MemberWithError (State a_awY0) r_awZu => Sem r_awZu a_awY0
- Polysemy.State: put :: forall s_az9t r_azb0. Member (State s_az9t) r_azb0 => s_az9t -> Sem r_azb0 ()
+ Polysemy.State: put :: forall s_awXY r_awZv. MemberWithError (State s_awXY) r_awZv => s_awXY -> Sem r_awZv ()
- Polysemy.Trace: trace :: forall r_aBEX. Member Trace r_aBEX => String -> Sem r_aBEX ()
+ Polysemy.Trace: trace :: forall r_azBe. MemberWithError Trace r_azBe => String -> Sem r_azBe ()
- Polysemy.Writer: censor :: forall o_aCaR r_aCdl a_aCaT. Member (Writer o_aCaR) r_aCdl => (o_aCaR -> o_aCaR) -> Sem r_aCdl a_aCaT -> Sem r_aCdl a_aCaT
+ Polysemy.Writer: censor :: forall o_aA5k r_aA7O a_aA5m. MemberWithError (Writer o_aA5k) r_aA7O => (o_aA5k -> o_aA5k) -> Sem r_aA7O a_aA5m -> Sem r_aA7O a_aA5m
- Polysemy.Writer: listen :: forall o_aCaR r_aCdj a_aCcX. Member (Writer o_aCaR) r_aCdj => Sem r_aCdj a_aCcX -> Sem r_aCdj (o_aCaR, a_aCcX)
+ Polysemy.Writer: listen :: forall o_aA5k r_aA7M a_aA7q. MemberWithError (Writer o_aA5k) r_aA7M => Sem r_aA7M a_aA7q -> Sem r_aA7M (o_aA5k, a_aA7q)
- Polysemy.Writer: tell :: forall o_aCaR r_aCdh. Member (Writer o_aCaR) r_aCdh => o_aCaR -> Sem r_aCdh ()
+ Polysemy.Writer: tell :: forall o_aA5k r_aA7K. MemberWithError (Writer o_aA5k) r_aA7K => o_aA5k -> Sem r_aA7K ()

Files

ChangeLog.md view
@@ -1,5 +1,19 @@ # Changelog for polysemy +## 0.6.0.0 (2019-07-04)++### Breaking Changes++- Changed the type of `runBatchOutput` to be more useful (thanks to @Infinisil)++### Other Changes++- **THE ERROR MESSAGES ARE SO MUCH BETTER** :party: :party: :party:+- Added `runEmbedded` to `Polysemy.IO`+- Added `runOutputAsList` to `Polysemy.Output` (thanks to @googleson78)+- Asymptotically improved the performance of `runTraceAsList` (thanks to+    @googleson78)+ ## 0.5.1.0 (2019-06-28)  - New combinators for `Polysemy.Error`: `fromEither` and `fromEitherM`
polysemy.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: e2b39ec6e1f466a89ba47a4f54b80b55c0b68a694c2dd08f5c46e0f6ca85437a+-- hash: fd80d4218e2d56a0c2af9f4bd89fc79c0ebce4fe968415430a6009ee91205586  name:           polysemy-version:        0.5.1.0+version:        0.6.0.0 synopsis:       Higher-order, low-boilerplate, zero-cost free monads. description:    Please see the README on GitHub at <https://github.com/isovector/polysemy#readme> category:       Language@@ -47,6 +47,7 @@       Polysemy.Internal       Polysemy.Internal.Combinators       Polysemy.Internal.CustomErrors+      Polysemy.Internal.CustomErrors.Redefined       Polysemy.Internal.Fixpoint       Polysemy.Internal.Forklift       Polysemy.Internal.Kind@@ -80,16 +81,22 @@     , template-haskell >=2.12.0.0 && <3     , th-abstraction >=0.3.1.0 && <0.4     , transformers >=0.5.2.0 && <0.6+    , type-errors >=0.2.0.0     , unagi-chan >=0.4.0.0 && <0.5   if impl(ghc < 8.6)     default-extensions: MonadFailDesugaring TypeInType+  if impl(ghc >= 8.6)+    build-depends:+        loopbreaker >=0.1 && <0.2   if flag(dump-core)-    ghc-options: -fplugin=DumpCore -fplugin-opt DumpCore:core-html+    ghc-options: -fplugin=DumpCore -fplugin-opt=DumpCore:core-html     build-depends:         dump-core   if impl(ghc < 8.2.2)     build-depends:         unsupported-ghc-version >1 && <1+  if impl(ghc >= 8.6)+    ghc-options: -fplugin=Loopbreaker   if flag(error-messages)     cpp-options: -DCABAL_SERIOUSLY_CMON_MATE   else@@ -132,9 +139,13 @@     , template-haskell >=2.12.0.0 && <3     , th-abstraction >=0.3.1.0 && <0.4     , transformers >=0.5.2.0 && <0.6+    , type-errors >=0.2.0.0     , unagi-chan >=0.4.0.0 && <0.5   if impl(ghc < 8.6)     default-extensions: MonadFailDesugaring TypeInType+  if impl(ghc >= 8.6)+    build-depends:+        loopbreaker >=0.1 && <0.2   default-language: Haskell2010  benchmark polysemy-bench@@ -160,7 +171,11 @@     , template-haskell >=2.12.0.0 && <3     , th-abstraction >=0.3.1.0 && <0.4     , transformers >=0.5.2.0 && <0.6+    , type-errors >=0.2.0.0     , unagi-chan >=0.4.0.0 && <0.5   if impl(ghc < 8.6)     default-extensions: MonadFailDesugaring TypeInType+  if impl(ghc >= 8.6)+    build-depends:+        loopbreaker >=0.1 && <0.2   default-language: Haskell2010
src/Polysemy/Async.hs view
@@ -50,7 +50,7 @@         Async a -> do           ma  <- runT a           ins <- getInspectorT-          fa  <- sendM $ A.async $ lower $ runAsync_b ma+          fa  <- sendM $ A.async $ lower $ runAsync ma           pureT $ fmap (inspect ins) fa          Await a -> pureT =<< sendM (A.wait a)@@ -58,14 +58,6 @@ {-# INLINE runAsync #-}  -runAsync_b-    :: LastMember (Lift IO) r-    => Sem (Async ': r) a-    -> Sem r a-runAsync_b = runAsync-{-# NOINLINE runAsync_b #-}-- ------------------------------------------------------------------------------ -- | Run an 'Async' effect via in terms of 'A.async'. --@@ -83,18 +75,10 @@         Async a -> do           ma  <- runT a           ins <- getInspectorT-          fa  <- sendM $ A.async $ lower $ runAsyncInIO_b lower ma+          fa  <- sendM $ A.async $ lower $ runAsyncInIO lower ma           pureT $ fmap (inspect ins) fa          Await a -> pureT =<< sendM (A.wait a)     )  m {-# INLINE runAsyncInIO #-}--runAsyncInIO_b-    :: Member (Lift IO) r-    => (forall x. Sem r x -> IO x)-    -> Sem (Async ': r) a-    -> Sem r a-runAsyncInIO_b = runAsyncInIO-{-# NOINLINE runAsyncInIO_b #-} 
src/Polysemy/Error.hs view
@@ -74,29 +74,23 @@   case decomp u of     Left x -> E.ExceptT $ k $       weave (Right ())-            (either (pure . Left) runError_b)+            (either (pure . Left) runError)             hush             x     Right (Yo (Throw e) _ _ _ _) -> E.throwE e     Right (Yo (Catch try handle) s d y _) ->       E.ExceptT $ usingSem k $ do-        ma <- runError_b $ d $ try <$ s+        ma <- runError $ d $ try <$ s         case ma of           Right a -> pure . Right $ y a           Left e -> do-            ma' <- runError_b $ d $ (<$ s) $ handle e+            ma' <- runError $ d $ (<$ s) $ handle e             case ma' of               Left e' -> pure $ Left e'               Right a -> pure . Right $ y a {-# INLINE runError #-} -runError_b-    :: Sem (Error e ': r) a-    -> Sem r (Either e a)-runError_b = runError-{-# NOINLINE runError_b #-} - ------------------------------------------------------------------------------ -- | Transform one 'Error' into another. This function can be used to aggregate -- multiple errors into a single type.@@ -169,19 +163,8 @@     is <- getInitialStateT     t  <- runT try     h  <- bindT handle-    let runIt = lower . runErrorAsExc_b lower+    let runIt = lower . runErrorAsExc lower     sendM $ X.catch (runIt t) $ \(se :: WrappedExc e) ->       runIt $ h $ unwrapExc se <$ is {-# INLINE runErrorAsExc #-}---runErrorAsExc_b-    :: ( Typeable e-       , Member (Lift IO) r-       )-    => (∀ x. Sem r x -> IO x)-    -> Sem (Error e ': r) a-    -> Sem r a-runErrorAsExc_b = runErrorAsExc-{-# NOINLINE runErrorAsExc_b #-} 
src/Polysemy/IO.hs view
@@ -3,10 +3,13 @@ module Polysemy.IO   ( -- * Interpretations     runIO+  , runEmbedded   ) where -import Polysemy import Control.Monad.IO.Class+import Polysemy+import Polysemy.Internal+import Polysemy.Internal.Union   ------------------------------------------------------------------------------@@ -40,4 +43,31 @@     -> Sem r a runIO = interpret $ sendM . liftIO @m . unLift {-# INLINE runIO #-}+++------------------------------------------------------------------------------+-- | Given some @'MonadIO' m@, interpret all @'Lift' m@ actions in that monad+-- at once. This is useful for interpreting effects like databases, which use+-- their own monad for describing actions.+--+-- This function creates a thread, and so should be compiled with @-threaded@.+--+-- TODO(sandy): @since+runEmbedded+    :: ( LastMember (Lift IO) r+       , MonadIO m+       )+    => (forall x. m x -> IO x)  -- ^ The means of running this monad.+    -> Sem (Lift m ': r) a+    -> Sem r a+runEmbedded run_m (Sem m) = withLowerToIO $ \lower _ ->+  run_m $ m $ \u ->+    case decomp u of+      Left x -> liftIO+              . lower+              . liftSem+              $ hoist (runEmbedded run_m) x++      Right (Yo (Lift wd) s _ y _) ->+        fmap y $ fmap (<$ s) wd 
src/Polysemy/Internal.hs view
@@ -256,20 +256,15 @@ -- | Introduce an effect into 'Sem'. Analogous to -- 'Control.Monad.Class.Trans.lift' in the mtl ecosystem raise :: ∀ e r a. Sem r a -> Sem (e ': r) a-raise = hoistSem $ hoist raise_b . weaken+raise = hoistSem $ hoist raise . weaken {-# INLINE raise #-}  -raise_b :: Sem r a -> Sem (e ': r) a-raise_b = raise-{-# NOINLINE raise_b #-}-- ------------------------------------------------------------------------------ -- | Like 'raise', but introduces a new effect underneath the head of the -- list. raiseUnder :: ∀ e2 e1 r a. Sem (e1 ': r) a -> Sem (e1 ': e2 ': r) a-raiseUnder = hoistSem $ hoist raiseUnder_b . weakenUnder+raiseUnder = hoistSem $ hoist raiseUnder . weakenUnder   where     weakenUnder :: ∀ m x. Union (e1 ': r) m x -> Union (e1 ': e2 ': r) m x     weakenUnder (Union SZ a) = Union SZ a@@ -278,16 +273,11 @@ {-# INLINE raiseUnder #-}  -raiseUnder_b :: Sem (e1 ': r) a -> Sem (e1 ': e2 ': r) a-raiseUnder_b = raiseUnder-{-# NOINLINE raiseUnder_b #-}-- ------------------------------------------------------------------------------ -- | Like 'raise', but introduces two new effects underneath the head of the -- list. raiseUnder2 :: ∀ e2 e3 e1 r a. Sem (e1 ': r) a -> Sem (e1 ': e2 ': e3 ': r) a-raiseUnder2 = hoistSem $ hoist raiseUnder2_b . weakenUnder2+raiseUnder2 = hoistSem $ hoist raiseUnder2 . weakenUnder2   where     weakenUnder2 ::  ∀ m x. Union (e1 ': r) m x -> Union (e1 ': e2 ': e3 ': r) m x     weakenUnder2 (Union SZ a) = Union SZ a@@ -296,27 +286,17 @@ {-# INLINE raiseUnder2 #-}  -raiseUnder2_b :: Sem (e1 ': r) a -> Sem (e1 ': e2 ': e3 ': r) a-raiseUnder2_b = raiseUnder2-{-# NOINLINE raiseUnder2_b #-}-- ------------------------------------------------------------------------------ -- | Like 'raise', but introduces two new effects underneath the head of the -- list. raiseUnder3 :: ∀ e2 e3 e4 e1 r a. Sem (e1 ': r) a -> Sem (e1 ': e2 ': e3 ': e4 ': r) a-raiseUnder3 = hoistSem $ hoist raiseUnder3_b . weakenUnder3+raiseUnder3 = hoistSem $ hoist raiseUnder3 . weakenUnder3   where     weakenUnder3 ::  ∀ m x. Union (e1 ': r) m x -> Union (e1 ': e2 ': e3 ': e4 ': r) m x     weakenUnder3 (Union SZ a) = Union SZ a     weakenUnder3 (Union (SS n) a) = Union (SS (SS (SS (SS n)))) a     {-# INLINE weakenUnder3 #-} {-# INLINE raiseUnder3 #-}---raiseUnder3_b :: Sem (e1 ': r) a -> Sem (e1 ': e2 ': e3 ': e4 ': r) a-raiseUnder3_b = raiseUnder3-{-# NOINLINE raiseUnder3_b #-}   ------------------------------------------------------------------------------
src/Polysemy/Internal/Combinators.hs view
@@ -48,7 +48,7 @@ -- | The simplest way to produce an effect handler. Interprets an effect @e@ by -- transforming it into other effects inside of @r@. interpret-    :: FirstOrder m0 e "interpret"+    :: FirstOrder e "interpret"     => (∀ x m. e m x -> Sem r x)        -- ^ A natural transformation from the handled effect to other effects        -- already in 'Sem'.@@ -72,12 +72,13 @@     -> Sem r a interpretH f (Sem m) = m $ \u ->   case decomp u of-    Left  x -> liftSem $ hoist (interpretH_b f) x+    Left  x -> liftSem $ hoist (interpretH f) x     Right (Yo e s d y v) -> do       a <- runTactics s d v $ f e       pure $ y a {-# INLINE interpretH #-} + ------------------------------------------------------------------------------ -- | A highly-performant combinator for interpreting an effect statefully. See -- 'stateful' for a more user-friendly variety of this function.@@ -92,13 +93,14 @@         Left x -> S.StateT $ \s' ->           k . fmap swap             . weave (s', ())-                    (uncurry $ interpretInStateT_b f)+                    (uncurry $ interpretInStateT f)                     (Just . snd)             $ x         Right (Yo e z _ y _) ->           fmap (y . (<$ z)) $ S.mapStateT (usingSem k) $ f e {-# INLINE interpretInStateT #-} + ------------------------------------------------------------------------------ -- | A highly-performant combinator for interpreting an effect statefully. See -- 'stateful' for a more user-friendly variety of this function.@@ -113,13 +115,14 @@         Left x -> LS.StateT $ \s' ->           k . fmap swap             . weave (s', ())-                    (uncurry $ interpretInLazyStateT_b f)+                    (uncurry $ interpretInLazyStateT f)                     (Just . snd)             $ x         Right (Yo e z _ y _) ->           fmap (y . (<$ z)) $ LS.mapStateT (usingSem k) $ f e {-# INLINE interpretInLazyStateT #-} + ------------------------------------------------------------------------------ -- | Like 'interpret', but with access to an intermediate state @s@. stateful@@ -154,7 +157,7 @@     -> Sem (e2 ': r) a reinterpretH f (Sem m) = Sem $ \k -> m $ \u ->   case decompCoerce u of-    Left x  -> k $ hoist (reinterpretH_b f) $ x+    Left x  -> k $ hoist (reinterpretH f) $ x     Right (Yo e s d y v) -> do       a <- usingSem k $ runTactics s (raiseUnder . d) v $ f e       pure $ y a@@ -168,8 +171,8 @@ -- 'Polysemy.State.runState', meaning it's free to 'reinterpret' in terms of -- the 'Polysemy.State.State' effect and immediately run it. reinterpret-    :: forall e1 e2 m0 r a-     . FirstOrder m0 e1 "reinterpret"+    :: forall e1 e2 r a+     . FirstOrder e1 "reinterpret"     => (∀ m x. e1 m x -> Sem (e2 ': r) x)        -- ^ A natural transformation from the handled effect to the new effect.     -> Sem (e1 ': r) a@@ -191,7 +194,7 @@     -> Sem (e2 ': e3 ': r) a reinterpret2H f (Sem m) = Sem $ \k -> m $ \u ->   case decompCoerce u of-    Left x  -> k $ weaken $ hoist (reinterpret2H_b f) $ x+    Left x  -> k $ weaken $ hoist (reinterpret2H f) $ x     Right (Yo e s d y v) -> do       a <- usingSem k $ runTactics s (raiseUnder2 . d) v $ f e       pure $ y a@@ -201,8 +204,8 @@ ------------------------------------------------------------------------------ -- | Like 'reinterpret', but introduces /two/ intermediary effects. reinterpret2-    :: forall e1 e2 e3 m0 r a-     . FirstOrder m0 e1 "reinterpret2"+    :: forall e1 e2 e3 r a+     . FirstOrder e1 "reinterpret2"     => (∀ m x. e1 m x -> Sem (e2 ': e3 ': r) x)        -- ^ A natural transformation from the handled effect to the new effects.     -> Sem (e1 ': r) a@@ -223,7 +226,7 @@     -> Sem (e2 ': e3 ': e4 ': r) a reinterpret3H f (Sem m) = Sem $ \k -> m $ \u ->   case decompCoerce u of-    Left x  -> k . weaken . weaken . hoist (reinterpret3H_b f) $ x+    Left x  -> k . weaken . weaken . hoist (reinterpret3H f) $ x     Right (Yo e s d y v) -> do       a <- usingSem k $ runTactics s (raiseUnder3 . d) v $ f e       pure $ y a@@ -233,8 +236,8 @@ ------------------------------------------------------------------------------ -- | Like 'reinterpret', but introduces /three/ intermediary effects. reinterpret3-    :: forall e1 e2 e3 e4 m0 r a-     . FirstOrder m0 e1 "reinterpret3"+    :: forall e1 e2 e3 e4 r a+     . FirstOrder e1 "reinterpret3"     => (∀ m x. e1 m x -> Sem (e2 ': e3 ': e4 ': r) x)        -- ^ A natural transformation from the handled effect to the new effects.     -> Sem (e1 ': r) a@@ -249,7 +252,7 @@ -- intercept other effects and insert logic around them. intercept     :: ( Member e r-       , FirstOrder m0 e "intercept"+       , FirstOrder e "intercept"        )     => (∀ x m. e m x -> Sem r x)        -- ^ A natural transformation from the handled effect to other effects@@ -277,67 +280,5 @@   case prj u of     Just (Yo e s d y v) ->       usingSem k $ fmap y $ runTactics s (raise . d) v $ f e-    Nothing -> k $ hoist (interceptH_b f) u+    Nothing -> k $ hoist (interceptH f) u {-# INLINE interceptH #-}------------------------------------------------------------------------------------ Loop breakers-interpretH_b-    :: (∀ x m . e m x -> Tactical e m r x)-    -> Sem (e ': r) a-    -> Sem r a-interpretH_b = interpretH-{-# NOINLINE interpretH_b #-}---interceptH_b-    :: Member e r-    => (∀ x m. e m x -> Tactical e m r x)-    -> Sem r a-    -> Sem r a-interceptH_b = interceptH-{-# NOINLINE interceptH_b #-}---interpretInStateT_b-    :: (∀ x m. e m x -> S.StateT s (Sem r) x)-    -> s-    -> Sem (e ': r) a-    -> Sem r (s, a)-interpretInStateT_b = interpretInStateT-{-# NOINLINE interpretInStateT_b #-}---interpretInLazyStateT_b-    :: (∀ x m. e m x -> LS.StateT s (Sem r) x)-    -> s-    -> Sem (e ': r) a-    -> Sem r (s, a)-interpretInLazyStateT_b = interpretInLazyStateT-{-# NOINLINE interpretInLazyStateT_b #-}---reinterpretH_b-    :: (∀ m x. e1 m x -> Tactical e1 m (e2 ': r) x)-    -> Sem (e1 ': r) a-    -> Sem (e2 ': r) a-reinterpretH_b = reinterpretH-{-# NOINLINE reinterpretH_b #-}---reinterpret2H_b-    :: (∀ m x. e1 m x -> Tactical e1 m (e2 ': e3 ': r) x)-    -> Sem (e1 ': r) a-    -> Sem (e2 ': e3 ': r) a-reinterpret2H_b = reinterpret2H-{-# NOINLINE reinterpret2H_b #-}---reinterpret3H_b-    :: (∀ m x. e1 m x -> Tactical e1 m (e2 ': e3 ': e4 ': r) x)-    -> Sem (e1 ': r) a-    -> Sem (e2 ': e3 ': e4 ': r) a-reinterpret3H_b = reinterpret3H-{-# NOINLINE reinterpret3H_b #-}-
src/Polysemy/Internal/CustomErrors.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE AllowAmbiguousTypes  #-} {-# LANGUAGE ConstraintKinds      #-}+{-# LANGUAGE TemplateHaskell      #-} {-# LANGUAGE TypeFamilies         #-} {-# LANGUAGE UndecidableInstances #-} @@ -7,20 +8,27 @@  module Polysemy.Internal.CustomErrors   ( AmbiguousSend-  , Break+  , WhenStuck   , FirstOrder   , UnhandledEffect   , DefiningModule   , DefiningModuleForEffect   ) where -import Data.Coerce import Data.Kind import Fcf import GHC.TypeLits import Polysemy.Internal.Kind+import Polysemy.Internal.CustomErrors.Redefined+import Type.Errors hiding (IfStuck, WhenStuck, UnlessStuck)  +------------------------------------------------------------------------------+-- | The module this effect was originally defined in. This type family is used+-- only for providing better error messages.+--+-- Calls to 'Polysemy.Internal.TH.Effect.makeSem' will automatically give+-- instances of 'DefiningModule'. type family DefiningModule (t :: k) :: Symbol  type family DefiningModuleForEffect (e :: k) :: Symbol where@@ -28,20 +36,38 @@   DefiningModuleForEffect e     = DefiningModule e  -data T1 m a+-- TODO(sandy): Put in type-errors+type ShowTypeBracketed t = 'Text "("+                     ':<>: 'ShowType t+                     ':<>: 'Text ")" -type family Break (c :: Constraint)-                  (rep :: Effect) :: Constraint where-  Break _ T1 = ((), ())-  Break _ c  = () +------------------------------------------------------------------------------+-- | The constructor of the effect row --- it's either completely polymorphic,+-- a nil, or a cons.+data EffectRowCtor = TyVarR | NilR | ConsR -type family IfStuck (tyvar :: k) (b :: k1) (c :: Exp k1) :: k1 where-  IfStuck T1 b c = b-  IfStuck a  b c = Eval c +------------------------------------------------------------------------------+-- | Given that @r@ isn't stuck, determine which constructor it has.+type family UnstuckRState (r :: EffectRow) :: EffectRowCtor where+  UnstuckRState '[]      = 'NilR+  UnstuckRState (_ ': _) = 'ConsR -type AmbigousEffectMessage r e t vs =++------------------------------------------------------------------------------+-- | Put brackets around @r@ if it's a cons.+type family ShowRQuoted (rstate :: EffectRowCtor) (r :: EffectRow) :: ErrorMessage where+  ShowRQuoted 'TyVarR r = 'ShowType r+  ShowRQuoted 'NilR   r = 'ShowType r+  ShowRQuoted 'ConsR  r = ShowTypeBracketed r+++type AmbigousEffectMessage (rstate :: EffectRowCtor)+                           (r :: EffectRow)+                           (e :: k)+                           (t :: Effect)+                           (vs :: [Type]) =         ( 'Text "Ambiguous use of effect '"     ':<>: 'ShowType e     ':<>: 'Text "'"@@ -49,51 +75,45 @@     ':$$: 'Text "  add (Member ("     ':<>: 'ShowType t     ':<>: 'Text ") "-    ':<>: 'ShowType r+    ':<>: ShowRQuoted rstate r     ':<>: 'Text ") to the context of "     ':$$: 'Text "    the type signature"     ':$$: 'Text "If you already have the constraint you want, instead"     ':$$: 'Text "  add a type application to specify"     ':$$: 'Text "    "-    ':<>: PrettyPrint vs+    ':<>: PrettyPrintList vs     ':<>: 'Text " directly, or activate polysemy-plugin which"     ':$$: 'Text "      can usually infer the type correctly."         ) -type family PrettyPrint (vs :: [k]) where-  PrettyPrint '[a] =-    'Text "'" ':<>: 'ShowType a ':<>: 'Text "'"-  PrettyPrint '[a, b] =-    'Text "'" ':<>: 'ShowType a ':<>: 'Text "', and "-    ':<>:-    'Text "'" ':<>: 'ShowType b ':<>: 'Text "'"-  PrettyPrint (a ': vs) =-    'Text "'" ':<>: 'ShowType a ':<>: 'Text "', "-    ':<>: PrettyPrint vs+type AmbiguousSend r e =+      (IfStuck r+        (AmbiguousSendError 'TyVarR r e)+        (Pure (AmbiguousSendError (UnstuckRState r) r e)))  -type family AmbiguousSend r e where-  AmbiguousSend r (e a b c d f) =-    TypeError (AmbigousEffectMessage r e (e a b c d f) '[a, b c d f])+type family AmbiguousSendError rstate r e where+  AmbiguousSendError rstate r (e a b c d f) =+    TypeError (AmbigousEffectMessage rstate r e (e a b c d f) '[a, b c d f]) -  AmbiguousSend r (e a b c d) =-    TypeError (AmbigousEffectMessage r e (e a b c d) '[a, b c d])+  AmbiguousSendError rstate r (e a b c d) =+    TypeError (AmbigousEffectMessage rstate r e (e a b c d) '[a, b c d]) -  AmbiguousSend r (e a b c) =-    TypeError (AmbigousEffectMessage r e (e a b c) '[a, b c])+  AmbiguousSendError rstate r (e a b c) =+    TypeError (AmbigousEffectMessage rstate r e (e a b c) '[a, b c]) -  AmbiguousSend r (e a b) =-    TypeError (AmbigousEffectMessage r e (e a b) '[a, b])+  AmbiguousSendError rstate r (e a b) =+    TypeError (AmbigousEffectMessage rstate r e (e a b) '[a, b]) -  AmbiguousSend r (e a) =-    TypeError (AmbigousEffectMessage r e (e a) '[a])+  AmbiguousSendError rstate r (e a) =+    TypeError (AmbigousEffectMessage rstate r e (e a) '[a]) -  AmbiguousSend r e =+  AmbiguousSendError rstate r e =     TypeError         ( 'Text "Could not deduce: (Member "     ':<>: 'ShowType e     ':<>: 'Text " "-    ':<>: 'ShowType r+    ':<>: ShowRQuoted rstate r     ':<>: 'Text ") "     ':$$: 'Text "Fix:"     ':$$: 'Text "  add (Member "@@ -105,37 +125,26 @@         )  ----type family FirstOrderError e (fn :: Symbol) :: k where-  FirstOrderError e fn =-    TypeError ( 'Text "'"-          ':<>: 'ShowType e-          ':<>: 'Text "' is higher-order, but '"-          ':<>: 'Text fn-          ':<>: 'Text "' can help only"-          ':$$: 'Text "with first-order effects."-          ':$$: 'Text "Fix:"-          ':$$: 'Text "  use '"-          ':<>: 'Text fn-          ':<>: 'Text "H' instead."-              )+data FirstOrderErrorFcf :: k -> Symbol -> Exp Constraint+type instance Eval (FirstOrderErrorFcf e fn) = $(te[t|+    UnlessPhantom+        (e PHANTOM)+        ( 'Text "'"+    ':<>: 'ShowType e+    ':<>: 'Text "' is higher-order, but '"+    ':<>: 'Text fn+    ':<>: 'Text "' can help only"+    ':$$: 'Text "with first-order effects."+    ':$$: 'Text "Fix:"+    ':$$: 'Text "  use '"+    ':<>: 'Text fn+    ':<>: 'Text "H' instead."+        ) |])  ------------------------------------------------------------------------------ -- | This constraint gives helpful error messages if you attempt to use a -- first-order combinator with a higher-order type.------ Note that the parameter 'm' is only required to work around supporting--- versions of GHC without QuantifiedConstraints-type FirstOrder m e fn = IfStuck e (() :: Constraint) (FirstOrderFcf m e fn)--data FirstOrderFcf-    :: (Type -> Type)-    -> Effect-    -> Symbol-    -> Exp Constraint-type instance Eval (FirstOrderFcf m e fn) = Coercible (e m) (e (FirstOrderError e fn))+type FirstOrder (e :: Effect) fn = UnlessStuck e (FirstOrderErrorFcf e fn)   ------------------------------------------------------------------------------@@ -155,12 +164,13 @@   ':<>: 'Text (DefiningModuleForEffect e)   ':<>: 'Text "'" -type family BreakSym (z :: k -> k) e (c :: Constraint)-                       (rep :: Symbol) :: k where-  BreakSym _ e _ "" =  TypeError (UnhandledEffectMsg e ':$$: CheckDocumentation e)-  BreakSym z e _ c  = z (TypeError (UnhandledEffectMsg e ':$$: CheckDocumentation e))+type family UnhandledEffect e where+  UnhandledEffect e =+    IfStuck (DefiningModule e)+            (TypeError (UnhandledEffectMsg e))+            (DoError (UnhandledEffectMsg e ':$$: CheckDocumentation e)) -type family UnhandledEffect z e where-  UnhandledEffect z e =-    BreakSym z e (TypeError (UnhandledEffectMsg e)) (DefiningModuleForEffect e)++data DoError :: ErrorMessage -> Exp k+type instance Eval (DoError a) = TypeError a 
+ src/Polysemy/Internal/CustomErrors/Redefined.hs view
@@ -0,0 +1,73 @@+{-# LANGUAGE ConstraintKinds #-}++------------------------------------------------------------------------------+-- | This code is copied verbatim from 'Type.Errors' due to limitations in the+-- (GHC 8.6) plugin machinery. See+-- <https://github.com/polysemy-research/polysemy/issues/152 #152> for more+-- info.+module Polysemy.Internal.CustomErrors.Redefined where++import Type.Errors hiding (IfStuck, WhenStuck, UnlessStuck)+++------------------------------------------------------------------------------+-- | @'IfStuck' expr b c@ leaves @b@ in the residual constraints whenever+-- @expr@ is stuck, otherwise it 'Eval'uates @c@.+type family IfStuck (expr :: k) (b :: k1) (c :: Exp k1) :: k1 where+  -- The type pattern @_ Foo@ is interpretered by the compiler as being of+  -- any kind. This is great and exactly what we want here, except that things+  -- like @forall s. Maybe s@ will get stuck on it.+  --+  -- So instead, we just propagate out 100 of these type variables and assume+  -- that 100 type variables ought to be enough for anyone.+  IfStuck (_ AnythingOfAnyKind AnythingOfAnyKind AnythingOfAnyKind+             AnythingOfAnyKind AnythingOfAnyKind AnythingOfAnyKind+             AnythingOfAnyKind AnythingOfAnyKind AnythingOfAnyKind+             AnythingOfAnyKind AnythingOfAnyKind AnythingOfAnyKind+             AnythingOfAnyKind AnythingOfAnyKind AnythingOfAnyKind+             AnythingOfAnyKind AnythingOfAnyKind AnythingOfAnyKind+             AnythingOfAnyKind AnythingOfAnyKind AnythingOfAnyKind+             AnythingOfAnyKind AnythingOfAnyKind AnythingOfAnyKind+             AnythingOfAnyKind AnythingOfAnyKind AnythingOfAnyKind+             AnythingOfAnyKind AnythingOfAnyKind AnythingOfAnyKind+             AnythingOfAnyKind AnythingOfAnyKind AnythingOfAnyKind+             AnythingOfAnyKind AnythingOfAnyKind AnythingOfAnyKind+             AnythingOfAnyKind AnythingOfAnyKind AnythingOfAnyKind+             AnythingOfAnyKind AnythingOfAnyKind AnythingOfAnyKind+             AnythingOfAnyKind AnythingOfAnyKind AnythingOfAnyKind+             AnythingOfAnyKind AnythingOfAnyKind AnythingOfAnyKind+             AnythingOfAnyKind AnythingOfAnyKind AnythingOfAnyKind+             AnythingOfAnyKind AnythingOfAnyKind AnythingOfAnyKind+             AnythingOfAnyKind AnythingOfAnyKind AnythingOfAnyKind+             AnythingOfAnyKind AnythingOfAnyKind AnythingOfAnyKind+             AnythingOfAnyKind AnythingOfAnyKind AnythingOfAnyKind+             AnythingOfAnyKind AnythingOfAnyKind AnythingOfAnyKind+             AnythingOfAnyKind AnythingOfAnyKind AnythingOfAnyKind+             AnythingOfAnyKind AnythingOfAnyKind AnythingOfAnyKind+             AnythingOfAnyKind AnythingOfAnyKind AnythingOfAnyKind+             AnythingOfAnyKind AnythingOfAnyKind AnythingOfAnyKind+             AnythingOfAnyKind AnythingOfAnyKind AnythingOfAnyKind+             AnythingOfAnyKind AnythingOfAnyKind AnythingOfAnyKind+             AnythingOfAnyKind AnythingOfAnyKind AnythingOfAnyKind+             AnythingOfAnyKind AnythingOfAnyKind AnythingOfAnyKind+             AnythingOfAnyKind AnythingOfAnyKind AnythingOfAnyKind+             AnythingOfAnyKind AnythingOfAnyKind AnythingOfAnyKind+             AnythingOfAnyKind AnythingOfAnyKind AnythingOfAnyKind+             AnythingOfAnyKind) b c = b+  IfStuck a                     b c = Eval c++data AnythingOfAnyKind+++------------------------------------------------------------------------------+-- | Like 'IfStuck', but specialized to the case when you don't want to do+-- anything if @expr@ isn't stuck.+type WhenStuck expr b   = IfStuck expr b NoErrorFcf+++------------------------------------------------------------------------------+-- | Like 'IfStuck', but leaves no residual constraint when @expr@ is stuck.+-- This can be used to ensure an expression /isn't/ stuck before analyzing it+-- further.+type UnlessStuck expr c = IfStuck expr NoError c+
src/Polysemy/Internal/Forklift.hs view
@@ -40,17 +40,9 @@       mvar <- newEmptyMVar       writeChan chan $ Forklift mvar x       takeMVar mvar-    Right y -> k $ hoist (runViaForklift_b chan) y+    Right y -> k $ hoist (runViaForklift chan) y {-# INLINE runViaForklift #-} --runViaForklift_b-    :: LastMember (Lift IO) r-    => InChan (Forklift r)-    -> Sem r a-    -> Sem '[Lift IO] a-runViaForklift_b = runViaForklift-{-# NOINLINE runViaForklift_b #-}   ------------------------------------------------------------------------------
src/Polysemy/Internal/TH/Common.hs view
@@ -31,7 +31,8 @@ import           Language.Haskell.TH import           Language.Haskell.TH.Datatype import           Language.Haskell.TH.PprLib-import           Polysemy.Internal (Sem, Member, send)+import           Polysemy.Internal (Sem, send)+import           Polysemy.Internal.Union (MemberWithError)  #if __GLASGOW_HASKELL__ >= 804 import           Prelude hiding ((<>))@@ -66,7 +67,7 @@ -- | @'makeMemberConstraint'' r type@ will produce a @Member type r@ -- constraint. makeMemberConstraint' :: Name -> Type -> Pred-makeMemberConstraint' r eff = classPred ''Member [eff, VarT r]+makeMemberConstraint' r eff = classPred ''MemberWithError [eff, VarT r]   ------------------------------------------------------------------------------
src/Polysemy/Internal/Tactics.hs view
@@ -191,7 +191,7 @@    -> Sem r a runTactics s d v (Sem m) = m $ \u ->   case decomp u of-    Left x -> liftSem $ hoist (runTactics_b s d v) x+    Left x -> liftSem $ hoist (runTactics s d v) x     Right (Yo GetInitialState s' _ y _) ->       pure $ y $ s <$ s'     Right (Yo (HoistInterpretation na) s' _ y _) -> do@@ -199,15 +199,4 @@     Right (Yo GetInspector s' _ y _) -> do       pure $ y $ Inspector v <$ s' {-# INLINE runTactics #-}---runTactics_b-   :: Functor f-   => f ()-   -> (∀ x. f (m x) -> Sem r2 (f x))-   -> (∀ x. f x -> Maybe x)-   -> Sem (Tactics f m r2 ': r) a-   -> Sem r a-runTactics_b = runTactics-{-# NOINLINE runTactics_b #-} 
src/Polysemy/Internal/Union.hs view
@@ -15,6 +15,7 @@   ( Union (..)   , Yo (..)   , Member+  , MemberWithError   , weave   , hoist   -- * Building Unions@@ -106,12 +107,16 @@ ------------------------------------------------------------------------------ -- | A proof that the effect @e@ is available somewhere inside of the effect -- stack @r@.-type Member e r = Member' e r+type Member e r = MemberNoError e r -type Member' e r =+type MemberWithError e r =   ( MemberNoError e r #ifndef NO_ERROR_MESSAGES-  , Break (AmbiguousSend r e) (IndexOf r (Found r e))+    -- NOTE: The plugin explicitly pattern matches on+    -- `WhenStuck (IndexOf r _) _`, so if you change this, make sure to change+    -- the corresponding implementation in+    -- Polysemy.Plugin.Fundep.solveBogusError+  , WhenStuck (IndexOf r (Found r e)) (AmbiguousSend r e) #endif   ) @@ -150,7 +155,7 @@  type family Found (ts :: [k]) (t :: k) :: Nat where #ifndef NO_ERROR_MESSAGES-  Found '[]       t = UnhandledEffect 'S t+  Found '[]       t = UnhandledEffect t #endif   Found (t ': ts) t = 'Z   Found (u ': ts) t = 'S (Found ts t)@@ -258,4 +263,3 @@  instance LastMember end '[end] where   decompLast = Right-
src/Polysemy/Output.hs view
@@ -8,13 +8,16 @@   , output      -- * Interpretations+  , runOutputAsList   , runFoldMapOutput   , runIgnoringOutput   , runBatchOutput   ) where +import Data.Bifunctor (first) import Polysemy import Polysemy.State+import Control.Monad (when)   ------------------------------------------------------------------------------@@ -27,6 +30,18 @@   ------------------------------------------------------------------------------+-- | Run an 'Output' effect by transforming it into a list of its values.+runOutputAsList+    :: forall o r a+     . Sem (Output o ': r) a+    -> Sem r ([o], a)+runOutputAsList = fmap (first reverse) . runState [] . reinterpret+  (\case+      Output o -> modify (o :)+  )+{-# INLINE runOutputAsList #-}++------------------------------------------------------------------------------ -- | Run an 'Output' effect by transforming it into a monoid. runFoldMapOutput     :: forall o m r a@@ -60,27 +75,22 @@ runBatchOutput     :: forall o r a      . Int+    -> Sem (Output o ': r) a     -> Sem (Output [o] ': r) a-    -> Sem (Output [[o]] ': r) a runBatchOutput 0 m = raise $ runIgnoringOutput m runBatchOutput size m = do-  ((_, res), a) <-+  ((c, res), a) <-     runState (0 :: Int, [] :: [o]) $ reinterpret2 (\case       Output o -> do-        (nacc, acc) <- get-        let no     = length o-            total  = mappend acc o-            ntotal = nacc + no--            emitting n ls-              | n >= size = do-                  let (emit, acc') = splitAt size ls-                  output [emit]-                  emitting (n - size) acc'-              | otherwise = pure (n, ls)-        (nacc', acc') <- emitting ntotal total-        put (nacc', acc')+        (count, acc) <- get+        let newCount = 1 + count+            newAcc = o : acc+        if newCount < size+          then put (newCount, newAcc)+          else do+            output (reverse newAcc)+            put (0 :: Int, [] :: [o])     ) m-  output [res]+  when (c > 0) $ output (reverse res)   pure a 
src/Polysemy/Reader.hs view
@@ -41,12 +41,8 @@   Ask -> pureT i   Local f m -> do     mm <- runT m-    raise $ runReader_b (f i) mm+    raise $ runReader (f i) mm {-# INLINE runReader #-}--runReader_b :: i -> Sem (Reader i ': r) a -> Sem r a-runReader_b = runReader-{-# NOINLINE runReader_b #-}   ------------------------------------------------------------------------------
src/Polysemy/Resource.hs view
@@ -94,7 +94,7 @@     u <- bindT use      let run_it :: Sem (Resource ': r) x -> IO x-        run_it = finish .@ runResourceInIO_b+        run_it = finish .@ runResourceInIO      sendM $ X.bracket (run_it a) (run_it . d) (run_it . u) @@ -104,9 +104,10 @@     u <- bindT use      let run_it :: Sem (Resource ': r) x -> IO x-        run_it = finish .@ runResourceInIO_b+        run_it = finish .@ runResourceInIO      sendM $ X.bracketOnError (run_it a) (run_it . d) (run_it . u)+{-# INLINE runResourceInIO #-}   ------------------------------------------------------------------------------@@ -123,7 +124,7 @@     d <- bindT dealloc     u <- bindT use -    let run_it = raise . runResource_b+    let run_it = raise . runResource     resource <- run_it a     result <- run_it $ u resource     _ <- run_it $ d resource@@ -134,7 +135,7 @@     d <- bindT dealloc     u <- bindT use -    let run_it = raise . runResource_b+    let run_it = raise . runResource      resource <- run_it a     result <- run_it $ u resource@@ -178,7 +179,7 @@      withLowerToIO $ \lower finish -> do       let done :: Sem (Resource ': r) x -> IO x-          done = lower . raise . runResourceBase_b+          done = lower . raise . runResourceBase       X.bracket           (done ma)           (\x -> done (mb x) >> finish)@@ -191,35 +192,9 @@      withLowerToIO $ \lower finish -> do       let done :: Sem (Resource ': r) x -> IO x-          done = lower . raise . runResourceBase_b+          done = lower . raise . runResourceBase       X.bracketOnError           (done ma)           (\x -> done (mb x) >> finish)           (done . mc) {-# INLINE runResourceBase #-}---runResource_b-    :: ∀ r a-     . Sem (Resource ': r) a-    -> Sem r a-runResource_b = runResource-{-# NOINLINE runResource_b #-}--runResourceInIO_b-    :: ∀ r a-     . Member (Lift IO) r-    => (∀ x. Sem r x -> IO x)-    -> Sem (Resource ': r) a-    -> Sem r a-runResourceInIO_b = runResourceInIO-{-# NOINLINE runResourceInIO_b #-}--runResourceBase_b-    :: forall r a-     . LastMember (Lift IO) r-    => Sem (Resource ': r) a-    -> Sem r a-runResourceBase_b = runResourceBase-{-# NOINLINE runResourceBase_b #-}-
src/Polysemy/State.hs view
@@ -105,15 +105,10 @@                       (\(s', m') -> fmap swap                                   $ S.runStateT m' s')                       (Just . snd)-              $ hoist hoistStateIntoStateT_b x+              $ hoist hoistStateIntoStateT x     Right (Yo Get z _ y _)     -> fmap (y . (<$ z)) $ S.get     Right (Yo (Put s) z _ y _) -> fmap (y . (<$ z)) $ S.put s {-# INLINE hoistStateIntoStateT #-}---hoistStateIntoStateT_b :: Sem (State s ': r) a -> S.StateT s (Sem r) a-hoistStateIntoStateT_b = hoistStateIntoStateT-{-# NOINLINE hoistStateIntoStateT_b #-}   {-# RULES "runState/reinterpret"
src/Polysemy/Trace.hs view
@@ -63,7 +63,7 @@ runTraceAsList     :: Sem (Trace ': r) a     -> Sem r ([String], a)-runTraceAsList = runFoldMapOutput @String (: []) . reinterpret (+runTraceAsList = runOutputAsList . reinterpret (   \case     Trace m -> output m   )
src/Polysemy/Writer.hs view
@@ -53,7 +53,7 @@         modify (`mappend` o) >>= pureT       Listen m -> do         mm <- runT m-        -- TODO(sandy): this is fucking stupid+        -- TODO(sandy): this is stupid         (o, fa) <- raise $ runWriter mm         pure $ fmap (o, ) fa       Censor f m -> do@@ -62,4 +62,3 @@         modify (`mappend` f o)         pure a   )-
test/OutputSpec.hs view
@@ -10,23 +10,27 @@ spec = parallel $ do   describe "runBatchOutput" $ do     it "should return nothing at batch size 0" $ do-      let (ms, ()) = runOutput 0 $ output @[Int] [0..100]+      let (ms, _) = runOutput 0 $ traverse (output @Int) [0..99]       length ms `shouldBe` 0 -    for_ (1 : [5..13] ++ [99..101]) $ \size -> do-      it ("should batch at size " ++ show size) $ do-          let (ms, ()) = runOutput size $ do-                output @[Int] [0]-                output @[Int] [1..4]-                output @[Int] [5..10]-                output @[Int] [11..12]-                output @[Int] [13..37]-                output @[Int] [38..99]-          length ms `shouldBe` (div 100 size + 1)-          length (head ms) `shouldBe` min size 100+    for_ (1 : [5..13] ++ [99..101]) $ \size ->+      context ("Works at size " ++ show size) $ do+        let (ms, _) = runOutput size $ traverse (output @Int) [0..99]+        it "returns the correct amount of batches" $+          length ms `shouldBe` div (100 + size - 1) size -- 100 `div` size but rounding up+        it "all batches except the last one are of the specified size" $+          map length (init ms) `shouldBe` replicate (length ms - 1) size+        it "returns all original elements in the correct order" $           concat ms `shouldBe` [0..99] +  describe "runOutputAsList" $+    it "should return elements in the order they were output" $+      let (xs, ()) = runOutputAsList' $ traverse_ (output @Int) [0..100]+       in xs `shouldBe` [0..100] -runOutput :: Int -> Sem '[Output [Int]] a -> ([[Int]], a)-runOutput size = run . runFoldMapOutput id . runBatchOutput size +runOutput :: Int -> Sem '[Output Int] a -> ([[Int]], a)+runOutput size = run . runFoldMapOutput (:[]) . runBatchOutput size++runOutputAsList' :: Sem '[Output Int] a -> ([Int], a)+runOutputAsList' = run . runOutputAsList
test/TypeErrors.hs view
@@ -10,6 +10,7 @@ -- >>> :m +Polysemy.Resource -- >>> :m +Polysemy.State -- >>> :m +Polysemy.Trace+-- >>> :m +Data.Maybe   --------------------------------------------------------------------------------@@ -44,14 +45,12 @@  -------------------------------------------------------------------------------- -- |--- TODO(sandy): should this mention 'Reader i' or just 'Reader'?--- -- >>> :{--- interpret @Reader $ \case+-- interpret @(Reader Bool) $ \case --   Ask -> undefined -- :} -- ...--- ... 'Reader i' is higher-order, but 'interpret' can help only+-- ... 'Reader Bool' is higher-order, but 'interpret' can help only -- ... with first-order effects. -- ... -- ... 'interpretH' instead.@@ -90,16 +89,12 @@ --  in runM foo''' -- :} -- ...--- ... Ambiguous use of effect 'Lift'+-- ... Unhandled effect 'Lift IO' -- ...--- ... add (Member (Lift IO) '[]) ...+-- ... Expected type: Sem '[Lift m] (Bool, ())+-- ... Actual type: Sem '[] (Bool, ()) -- ...------ PROBLEM: We're trying to run more effects than exist in the eff row. This is--- indeed a problem, but the error message isn't helpful.------ SOLUTION: Add a special case to `AmbiguousSend` when `r ~ '[]`.-runningTooManyEffects'WRONG = ()+runningTooManyEffects = ()   --------------------------------------------------------------------------------@@ -111,13 +106,9 @@ -- ... -- ... Ambiguous use of effect 'State' -- ...--- ... (Member (State ()) State Int : r) ...+-- ... (Member (State ()) (State Int : r)) ... -- ...------ PROBLEM: There should be parentheses around `State Int : r`------ SOLUTION: Emit parens only when the effect row is of the form `e1 ': ...`-missingParens'WRONG = ()+ambiguousSendInConcreteR = ()   --------------------------------------------------------------------------------@@ -128,40 +119,36 @@ --  in runM $ runResourceInIO foo -- :} -- ...--- ... Ambiguous use of effect 'Lift'+-- ... Couldn't match expected type ...+-- ... with actual type ...+-- ... Probable cause: ... is applied to too few arguments -- ...--- ... (Member (Lift IO) r0) ...+missingArgumentToRunResourceInIO = ()+++--------------------------------------------------------------------------------+-- |+-- >>> :{+-- existsKV :: Member (State (Maybe Int)) r => Sem r Bool+-- existsKV = isJust get+-- :} -- ...--- ... Could not deduce: (Member Resource r1)+-- ... Ambiguous use of effect 'State' -- ... ----- PROBLEM: This error is totally bogus. We forgot to give an argument to--- 'runResourceInIO'. For comparison, the standard error GHC gives in this case--- is significantly more helpful:------    <interactive>:192:13: error:---        • Couldn't match expected type ‘Sem '[Lift m] a’---                      with actual type ‘Sem (Resource : r0) a0 -> Sem r0 a0’---        • Probable cause: ‘runResourceInIO’ is applied to too few arguments---          In the second argument of ‘($)’, namely ‘runResourceInIO foo’---          In the expression: runM $ runResourceInIO foo---          In the expression:---            let---              foo :: Member Resource r => Sem r ()---              foo = undefined---            in runM $ runResourceInIO foo---        • Relevant bindings include---            it :: m a (bound at <interactive>:190:2)---    <interactive>:192:29: error:---        • Couldn't match expected type ‘Sem r0 x -> IO x’---                      with actual type ‘Sem r1 ()’---        • In the first argument of ‘runResourceInIO’, namely ‘foo’---          In the second argument of ‘($)’, namely ‘runResourceInIO foo’---          In the expression: runM $ runResourceInIO foo--------- SOLUTION: Honestly I'm not sure!-missingArgumentToRunResourceInIO'WRONG = ()-+-- NOTE: This is fixed by enabling the plugin!+missingFmap'PLUGIN = () +--------------------------------------------------------------------------------+-- |+-- >>> :{+-- foo :: Sem '[State Int, Lift IO] ()+-- foo = output ()+-- :}+-- ...+-- ... Unhandled effect 'Output ()'+-- ...+-- ... add an interpretation for 'Output ()'+-- ...+missingEffectInStack'WRONG = ()