-
Notifications
You must be signed in to change notification settings - Fork 74
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update docs for runTH and bindTH #394
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,8 +28,15 @@ import Polysemy.Internal.Union | |
-- effect @Tactics@, which is capable of rewriting monadic actions so they run | ||
-- in the correct stateful environment. | ||
-- | ||
-- Inside a 'Tactical', you're capable of running 'pureT', 'runT' and 'bindT' | ||
-- which are the main tools for rewriting monadic stateful environments. | ||
-- The @f@ type here is existential and corresponds to "whatever | ||
-- state the other effects want to keep track of." @f@ is always | ||
-- a 'Functor'. | ||
-- | ||
-- Inside a 'Tactical', you're capable of running 'pureT', 'runTSimple', 'bindTSimple', | ||
-- 'runT' and 'bindT', which are the main tools for rewriting monadic stateful environments. | ||
-- | ||
-- You should usually reach for 'runTSimple' and 'bindTSimple' first, as they are easier to use, | ||
-- albeit less powerful versions of 'runT' and 'bindT'. | ||
-- | ||
-- For example, consider trying to write an interpreter for | ||
-- 'Polysemy.Resource.Resource', whose effect is defined as: | ||
|
@@ -38,41 +45,53 @@ import Polysemy.Internal.Union | |
-- data 'Polysemy.Resource.Resource' m a where | ||
-- 'Polysemy.Resource.Bracket' :: m a -> (a -> m ()) -> (a -> m b) -> 'Polysemy.Resource.Resource' m b | ||
-- @ | ||
-- | ||
-- Here we have an @m a@ which clearly needs to be run first, and then | ||
-- subsequently call the @a -> m ()@ and @a -> m b@ arguments. In a 'Tactical' | ||
-- environment, we can write the threading code thusly: | ||
-- We can interpret this effect like so: | ||
-- | ||
-- @ | ||
-- 'Polysemy.Resource.Bracket' alloc dealloc use -> do | ||
-- alloc' <- 'runT' alloc | ||
-- dealloc' <- 'bindT' dealloc | ||
-- use' <- 'bindT' use | ||
-- runResource = Polysemy.interpretH $ \\case | ||
-- 'Polysemy.Resource.Bracket' alloc dealloc use -> do | ||
-- resource <- 'runTSimple' alloc | ||
-- result <- 'bindTSimple' use resource | ||
-- 'bindTSimple' dealloc resource | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is wrong, since this will have fresource <- runTSimple alloc
fresourceresult <- bindTSimple (\a -> ((,) a) <$> use a) fresource
bindTSimple (\(resource, result) -> result <$ dealloc resource) fresourceresult This is very complicated. Also, this documentation is misleading since this isn't actually how All in all, we should pick a different example than There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm, does the current example do the same thing regarding the "state inheritance"? This is the impression I was left with (and it also seems to be the point of the example), from the current documentation. I guess it would be misleading if the actual |
||
-- pure result | ||
-- @ | ||
-- | ||
-- where | ||
-- To run embedded higher-order actions (e.g. @alloc :: m a@s) we use 'runTSimple'. | ||
-- | ||
-- @ | ||
-- alloc' :: 'Polysemy.Sem' ('Polysemy.Resource.Resource' ': r) (f a1) | ||
-- dealloc' :: f a1 -> 'Polysemy.Sem' ('Polysemy.Resource.Resource' ': r) (f ()) | ||
-- use' :: f a1 -> 'Polysemy.Sem' ('Polysemy.Resource.Resource' ': r) (f x) | ||
-- @ | ||
-- If we have a kleisli action (e.g. @use :: a -> m b@) we can instead use 'bindTSimple'. | ||
-- | ||
-- The @f@ type here is existential and corresponds to "whatever | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unfortunately there is no long an example to attach this talking point to, and it seems rather important, as it explains the that a Is there some other example that can be given here to demonstrate this? @KingoftheHomeless @tek @TheMatten There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can't we just put it at the end of the doc comment, so that the association with the type decl is apparent? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok obviously that should be "top of the comment" 😄 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added it back near the top + another piece of documentation that I previously deleted |
||
-- state the other effects want to keep track of." @f@ is always | ||
-- a 'Functor'. | ||
-- Note that because of the types of @'bindTSimple' use resource@ and @'bindTSimple' dealloc resource@ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I also add this "same environment" comment back here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Haddock rendering doesn't do a great job of distinguishing |
||
-- both use @f a@, they must run in the same stateful environment. This | ||
-- means, for illustration, any 'Polysemy.State.put's run inside the @'bindTSimple' use resource@ | ||
-- block will not be visible inside of the @dealloc@ block. | ||
-- | ||
-- @alloc'@, @dealloc'@ and @use'@ are now in a form that can be | ||
-- easily consumed by your interpreter. At this point, simply bind | ||
-- them in the desired order and continue on your merry way. | ||
-- There are however some cases where the @\*Simple@ functions are not sufficient. | ||
-- | ||
-- We can see from the types of @dealloc'@ and @use'@ that since they both | ||
-- consume a @f a1@, they must run in the same stateful environment. This | ||
-- means, for illustration, any 'Polysemy.State.put's run inside the @use@ | ||
-- block will not be visible inside of the @dealloc@ block. | ||
-- Consider, for example, the 'Polysemy.Reader.local' action. | ||
-- | ||
-- In it, we want any inner computations to be executed with a __modified__ environment. | ||
-- | ||
-- This is not possible with 'runTSimple' and 'bindTSimple', because they automatically | ||
-- take the care to run all your embedded actions by using the current set of interpreters. | ||
-- | ||
-- Instead, we need to use 'runT' and 'bindT', which give more control over how inner actions are run. | ||
-- | ||
-- As an example, let's look at the implementation for running a 'Polysemy.Reader.Reader' | ||
-- with a constant value: | ||
-- | ||
-- @ | ||
-- 'Polysemy.Reader.runReader' i = 'Polysemy.interpretH' $ \\case | ||
-- 'Polysemy.Reader.Ask' -> pureT i | ||
-- 'Polysemy.Reader.Local' f m -> do | ||
-- mm <- 'runT' m | ||
tek marked this conversation as resolved.
Show resolved
Hide resolved
|
||
-- 'Polysemy.raise' $ 'Polysemy.Reader.runReader' (f i) mm | ||
-- @ | ||
-- | ||
-- We can see that there is a recursive call to 'Polysemy.Reader.runReader', which handles | ||
-- any other potential 'Polysemy.Reader' computations that might be present in our @m@. | ||
-- | ||
-- Power users may explicitly use 'getInitialStateT' and 'bindT' to construct | ||
-- whatever data flow they'd like; although this is usually unnecessary. | ||
-- The thing to note here is that the call is made with a __modified__ environment of @f i@ | ||
-- instead of the __initial__ @i@ that our interpreter was currently running with. | ||
type Tactical e m r x = ∀ f. Functor f | ||
=> Sem (WithTactics e f m r) (f x) | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added the "existential" comment back here.