* v1.3.0.0

* Update version and version bounds for polysemy and polysemy-plugin
This commit is contained in:
KingoftheHomeless 2020-02-13 21:21:32 +01:00 committed by GitHub
parent 8d49b677fc
commit 3c731186cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 116 additions and 52 deletions

View File

@ -1,5 +1,29 @@
# Changelog for polysemy
## 1.3.0.0 (2020-02-14)
### Breaking Changes
- The semantics for `runNonDet` when `<|>` is used inside a higher-order action
of another effect has been reverted to that of 1.1.0.0 and earlier.
(See [issue #246](https://github.com/polysemy-research/polysemy/issues/246))
- Type parameters for `outputToTrace` have been rearranged (thanks to
@juanpaucar)
### Other Changes
- Added `Bundle` effect, for bundling multiple effects into a single one.
- Added `Tagged` effect, for annotating and disambiguating identical effects.
- Added `View` effect, an `Input`-like effect for caching an expensive computation.
- Added `catchJust`
- Added `fromException`/`Via` and `fromExceptionSem`/`Via`
- Added `note`
- Added `try` and `tryJust`
- Added `runStateSTRef` and `stateToST`
- Added `execState` and `execLazyState`
- Added `Polysemy.Law`, which offers machinery for creating laws for effects.
- Added `Polysemy.Membership` for retrieving and making use of effect membership
proofs.
## 1.2.3.0 (2019-10-29)
- Polysemy now works on GHC 8.8.1 (thanks to @googleson78 and @sevanspowell)
@ -32,7 +56,7 @@
- Type variables for certain internal functions, `failToEmbed`, and
`atomicState'` have been rearranged.
## Other changes
### Other changes
- Added `Final` effect, an effect for embedding higher-order actions in the
final monad of the effect stack. Any interpreter should use this instead of
@ -260,4 +284,3 @@
- Changed the tyvars of `fromEitherM`, `runErrorAsAnother`, `runEmbedded`,
`asks` and `gets`

View File

@ -1,5 +1,5 @@
name: polysemy
version: 1.2.3.0
version: 1.3.0.0
github: "isovector/polysemy"
license: BSD3
author: "Sandy Maguire"

View File

@ -1,5 +1,11 @@
# Changelog for polysemy-plugin
## 0.2.5.0 (2020-10-14)
- Updated the lower bounds to `polysemy-1.3.0.0` because of changes to
`polysemy` internals
- Updated the test suite to test against `polysemy-1.3.0.0`.
## 0.2.4.0 (2019-10-29)
- The plugin now works on GHC 8.8.1 (thanks to @googleson78 and @sevanspowell)

View File

@ -1,5 +1,5 @@
name: polysemy-plugin
version: 0.2.4.0
version: 0.2.5.0
github: "isovector/polysemy"
license: BSD3
author: "Sandy Maguire"
@ -20,7 +20,7 @@ dependencies:
- base >= 4.9 && < 5
- ghc >= 8.4.4 && < 9
- ghc-tcplugins-extra >= 0.3 && < 0.4
- polysemy >= 0.6
- polysemy >= 1.3
- syb >= 0.7 && < 0.8
- transformers >= 0.5.2.0 && < 0.6
- containers >= 0.5 && < 0.7
@ -57,7 +57,7 @@ tests:
build-tools:
- hspec-discover
dependencies:
- polysemy >= 1.2.0.0
- polysemy >= 1.3.0.0
- polysemy-plugin
- hspec >= 2.6.0 && < 3
- should-not-typecheck >= 2.1.0 && < 3

View File

@ -4,10 +4,10 @@ cabal-version: 1.24
--
-- see: https://github.com/sol/hpack
--
-- hash: 82e62a325b42351fc99bb87c3d491920a5a047c179e686cd398c82a9870f5e46
-- hash: 48094f708e51c9466f041c84159f98dd8116f8573bdf02908880f68e2d8ed787
name: polysemy-plugin
version: 0.2.4.0
version: 0.2.5.0
synopsis: Disambiguate obvious uses of effects.
description: Please see the README on GitHub at <https://github.com/isovector/polysemy/tree/master/polysemy-plugin#readme>
category: Polysemy
@ -56,7 +56,7 @@ library
, containers >=0.5 && <0.7
, ghc >=8.4.4 && <9
, ghc-tcplugins-extra >=0.3 && <0.4
, polysemy >=0.6
, polysemy >=1.3
, syb >=0.7 && <0.8
, transformers >=0.5.2.0 && <0.6
default-language: Haskell2010
@ -88,7 +88,7 @@ test-suite polysemy-plugin-test
, ghc-tcplugins-extra >=0.3 && <0.4
, hspec >=2.6.0 && <3
, inspection-testing >=0.4.2 && <0.5
, polysemy >=1.2.0.0
, polysemy >=1.3.0.0
, polysemy-plugin
, should-not-typecheck >=2.1.0 && <3
, syb >=0.7 && <0.8

View File

@ -4,10 +4,10 @@ cabal-version: 1.24
--
-- see: https://github.com/sol/hpack
--
-- hash: 582807c5d69a34a9e991a77c6111532c05dbb54a5d7aa6662267b7af2d3047ee
-- hash: 0f1599ec8e1caf24489536a197f2eb261ecdfb3613fdc2f2221186cdb0f31a5e
name: polysemy
version: 1.2.3.0
version: 1.3.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
@ -96,7 +96,7 @@ library
, async >=2.2 && <3
, base >=4.9 && <5
, containers >=0.5 && <0.7
, first-class-families >=0.5.0.0 && <0.7
, first-class-families >=0.5.0.0 && <0.8
, mtl >=2.2.2 && <3
, stm >=2 && <3
, syb >=0.7 && <0.8
@ -157,7 +157,7 @@ test-suite polysemy-test
, base >=4.9 && <5
, containers >=0.5 && <0.7
, doctest >=0.16.0.1 && <0.17
, first-class-families >=0.5.0.0 && <0.7
, first-class-families >=0.5.0.0 && <0.8
, hspec >=2.6.0 && <3
, inspection-testing >=0.4.2 && <0.5
, mtl >=2.2.2 && <3
@ -189,7 +189,7 @@ benchmark polysemy-bench
, base >=4.9 && <5
, containers >=0.5 && <0.7
, criterion
, first-class-families >=0.5.0.0 && <0.7
, first-class-families >=0.5.0.0 && <0.8
, free
, freer-simple
, mtl

View File

@ -203,9 +203,9 @@ runError (Sem m) = Sem $ \k -> E.runExceptT $ m $ \u ->
hush
x
Right (Weaving (Throw e) _ _ _ _) -> E.throwE e
Right (Weaving (Catch try handle) s d y _) ->
Right (Weaving (Catch main handle) s d y _) ->
E.ExceptT $ usingSem k $ do
ma <- runError $ d $ try <$ s
ma <- runError $ d $ main <$ s
case ma of
Right a -> pure . Right $ y a
Left e -> do
@ -329,11 +329,11 @@ runErrorAsExc
-> Sem r a
runErrorAsExc lower = interpretH $ \case
Throw e -> embed $ X.throwIO $ WrappedExc e
Catch try handle -> do
Catch main handle -> do
is <- getInitialStateT
t <- runT try
m <- runT main
h <- bindT handle
let runIt = lower . runErrorAsExc lower
embed $ X.catch (runIt t) $ \(se :: WrappedExc e) ->
embed $ X.catch (runIt m) $ \(se :: WrappedExc e) ->
runIt $ h $ unwrapExc se <$ is
{-# INLINE runErrorAsExc #-}

View File

@ -415,7 +415,7 @@ subsume = subsumeUsing membership
-- _ -> Nothing
-- @
--
-- @since TODO
-- @since 1.3.0.0
subsumeUsing :: forall e r a. ElemOf e r -> Sem (e ': r) a -> Sem r a
subsumeUsing pr =
let

View File

@ -294,6 +294,8 @@ interceptH = interceptUsingH membership
--
-- This is useful in conjunction with 'Polysemy.Membership.tryMembership'
-- in order to conditionally perform 'intercept'.
--
-- @since 1.3.0.0
interceptUsing
:: FirstOrder e "interceptUsing"
=> ElemOf e r
@ -317,6 +319,8 @@ interceptUsing pr f = interceptUsingH pr $ \(e :: e m x) -> liftT @m $ f e
-- in order to conditionally perform 'interceptH'.
--
-- See the notes on 'Tactical' for how to use this function.
--
-- @since 1.3.0.0
interceptUsingH
:: ElemOf e r
-- ^ A proof that the handled effect exists in @r@.

View File

@ -171,6 +171,8 @@ type MemberNoError e r =
-- Due to technical reasons, @'ElemOf' e r@ is not powerful enough to
-- prove @'Member' e r@; however, it can still be used send actions of @e@
-- into @r@ by using 'Polysemy.Internal.subsumeUsing'.
--
-- @since 1.3.0.0
data ElemOf e r where
-- | @e@ is located at the head of the list.
Here :: ElemOf e (e ': r)

View File

@ -90,68 +90,97 @@ runWriterSTMAction write = interpretH $ \case
tvar <- newTVarIO mempty
switch <- newTVarIO False
fa <-
restore (wv (runWriterSTMAction (write' tvar switch) m' <$ s))
`onException` commit tvar switch id
o <- commit tvar switch id
restore (wv (runWriterSTMAction (writeListen tvar switch) m' <$ s))
`onException` commitListen tvar switch
o <- commitListen tvar switch
return $ (fmap . fmap) (o, ) fa
Pass m -> do
m' <- runT m
ins <- getInspectorT
raise $ withWeavingToFinal $ \s wv ins' -> mask $ \restore -> do
-- See below to understand how this works
tvar <- newTVarIO mempty
switch <- newTVarIO False
t <-
restore (wv (runWriterSTMAction (write' tvar switch) m' <$ s))
`onException` commit tvar switch id
_ <- commit tvar switch
restore (wv (runWriterSTMAction (writePass tvar switch) m' <$ s))
`onException` commitPass tvar switch id
commitPass tvar switch
(maybe id fst $ ins' t >>= inspect ins)
return $ (fmap . fmap) snd t
where
{- KingoftheHomeless:
'write'' is used by the argument computation to a 'listen' or 'pass'
in order to 'tell', rather than directly using the 'write'.
'writeListen'/'writePass' is used by the argument computation to a
'listen' or 'pass' in order to 'tell', rather than directly using
the provided 'write'.
This is because we need to temporarily store its
'tell's seperately in order for the 'listen'/'pass' to work
properly. Once the 'listen'/'pass' completes, we 'commit' the
changes done to the local tvar globally through 'write'.
'tell's locally in order for the 'listen'/'pass' to work
properly. In the case of 'listen', this is done in parallel with
the global 'write's. In the case of 'pass', the argument computation
doesn't use 'write' at all, and instead, when the computation completes,
commit the changes it made to the local tvar by 'commitPass',
globally 'write'ing it all at once.
('commitListen' serves only as a (likely unneeded)
safety measure.)
'commit' is protected by 'mask'+'onException'. Combine this
with the fact that the 'withWeavingToFinal' can't be interrupted
by pure errors emitted by effects (since these will be
'commitListen'/'commitPass' is protected by 'mask'+'onException'.
Combine this with the fact that the 'withWeavingToFinal' can't be
interrupted by pure errors emitted by effects (since these will be
represented as part of the functorial state), and we
guarantee that no writes will be lost if the argument computation
fails for whatever reason.
The argument computation to a 'listen'/'pass' may also spawn
The argument computation to a 'pass' may also spawn
asynchronous computations which do 'tell's of their own.
In order to make sure these 'tell's won't be lost once a
'listen'/'pass' completes, a switch is used to
control which tvar 'write'' writes to. The switch is flipped
'pass' completes, a switch is used to
control which tvar 'writePass' writes to. The switch is flipped
atomically together with commiting the writes of the local tvar
as part of 'commit'. Once the switch is flipped,
any asynchrounous computations spawned by the argument
any asynchronous computations spawned by the argument
computation will write to the global tvar instead of the local
tvar (which is no longer relevant), and thus no writes will be
lost.
-}
write' :: TVar o
-> TVar Bool
-> o
-> STM ()
write' tvar switch = \o -> do
writeListen :: TVar o
-> TVar Bool
-> o
-> STM ()
writeListen tvar switch = \o -> do
alreadyCommited <- readTVar switch
unless alreadyCommited $ do
s <- readTVar tvar
writeTVar tvar $! s <> o
write o
{-# INLINE writeListen #-}
writePass :: TVar o
-> TVar Bool
-> o
-> STM ()
writePass tvar switch = \o -> do
useGlobal <- readTVar switch
if useGlobal then
write o
else do
s <- readTVar tvar
writeTVar tvar $! s <> o
{-# INLINE writePass #-}
commit :: TVar o
-> TVar Bool
-> (o -> o)
-> IO o
commit tvar switch f = atomically $ do
commitListen :: TVar o
-> TVar Bool
-> IO o
commitListen tvar switch = atomically $ do
writeTVar switch True
readTVar tvar
{-# INLINE commitListen #-}
commitPass :: TVar o
-> TVar Bool
-> (o -> o)
-> IO ()
commitPass tvar switch f = atomically $ do
o <- readTVar tvar
let !o' = f o
-- Likely redundant, but doesn't hurt.
@ -159,7 +188,7 @@ runWriterSTMAction write = interpretH $ \case
unless alreadyCommited $
write o'
writeTVar switch True
return o'
{-# INLINE commitPass #-}
{-# INLINE runWriterSTMAction #-}

View File

@ -186,7 +186,7 @@ stateToIO s sem = do
------------------------------------------------------------------------------
-- | Run a 'State' effect by transforming it into operations over an 'STRef'.
--
-- @since TODO: version
-- @since 1.3.0.0
runStateSTRef
:: forall s st r a
. Member (Embed (ST st)) r
@ -224,7 +224,7 @@ runStateSTRef ref = interpret $ \case
-- stResult = runST ( (runM $ stateToST \@_ \@st undefined $ pure undefined) :: forall st. ST st (s, a) )
-- @
--
-- @since TODO: version
-- @since 1.3.0.0
stateToST
:: forall s st r a
. Member (Embed (ST st)) r