-
Notifications
You must be signed in to change notification settings - Fork 53
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
Simplified eliminators #207
Conversation
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.
Ready for review.
src/Control/Carrier/Choose/Church.hs
Outdated
@@ -25,6 +26,9 @@ import Prelude hiding (fail) | |||
runChoose :: (m b -> m b -> m b) -> (a -> m b) -> ChooseC m a -> m b | |||
runChoose fork leaf m = runChooseC m fork leaf | |||
|
|||
runChooseS :: (Applicative m, Semigroup b) => (a -> m b) -> ChooseC m a -> m b | |||
runChooseS leaf = runChoose (liftA2 (<>)) leaf |
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.
We could supply runChooseA
, but:
-
You’d be giving up the assurance that you’ll have a non-empty container of results.
-
You can always use
runChoose (liftA2 (<|>)) (pure . pure)
orrunChooseS Alt >=> getAlt
if you must.
By contrast, there’s no reason to supply runChooseM
as every Monoid
is already a Semigroup
.
runCull (CullC m) = runNonDetC (runReader False m) (<|>) pure empty | ||
-- prop> run (runCull (liftA2 (<|>)) (pure . pure) (pure empty) (pure a <|> pure b)) === [a, b] | ||
runCull :: (m b -> m b -> m b) -> (a -> m b) -> m b -> CullC m a -> m b | ||
runCull fork leaf nil = runNonDet fork leaf nil . runReader False . runCullC |
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.
This is much more flexible than the previous handlers employed (which required the use of another carrier for nondeterminism).
We no longer provide a handler interpreting into an underlying Alternative
instance; instead, runCull (<|>) pure empty
can be used, if one absolutely must.
@@ -58,7 +66,7 @@ instance Alternative (NonDetC m) where | |||
|
|||
instance Monad (NonDetC m) where | |||
NonDetC a >>= f = NonDetC $ \ fork leaf nil -> | |||
a fork (\ a' -> runNonDetC (f a') fork leaf nil) nil | |||
a fork (runNonDet fork leaf nil . f) nil |
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.
This was by no means the point of this PR, but it’s certainly a nice side benefit that we can use the eliminators point-free.
@@ -5,7 +5,7 @@ module Control.Carrier.Trace.Returning | |||
-- * Trace carrier | |||
, runTrace | |||
, TraceC(..) | |||
-- * Re-exports |
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.
conform!
@@ -36,5 +36,4 @@ cull m = send (Cull m pure) | |||
-- >>> import Test.QuickCheck | |||
-- >>> import Control.Carrier.Cull.Church | |||
-- >>> import Control.Carrier.NonDet.Church | |||
-- >>> import Control.Carrier.Pure |
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.
This is re-exported by Control.Carrier
, and I missed cleaning these up.
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.
Small quibbles that you can choose to fix or not, but other than that this is ready to go.
- The primary handlers (`runChoose`, `runNonDet`, `runCut`, `runCull`) take multiple continuations. | ||
- Handlers which return an `Alternative` are suffixed with `A`, e.g. `runNonDetA`. | ||
- Handlers which return a `Monoid` are suffixed with `M`, e.g. `runNonDetM`. | ||
- Handlers which return a `Semigroup` are suffixed with `S`, e.g. `runChooseS`. |
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.
Loving this.
import Prelude hiding (fail) | ||
|
||
runChoose :: (m b -> m b -> m b) -> (a -> m b) -> ChooseC m a -> m b | ||
runChoose fork leaf m = runChooseC m fork leaf | ||
|
||
runChooseS :: (Applicative m, S.Semigroup b) => (a -> m b) -> ChooseC m a -> m b |
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.
Can we get documentation for this, mentioning that it uses <>
to merge its results?
mfix (runChoose (liftA2 Fork) (pure . Leaf) | ||
mfix (runChoose | ||
(liftA2 Fork) | ||
(pure . Leaf) | ||
. f . fromJust . fold (Alt.<|>) Just) |
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.
Can we use something more descriptive than fromJust
here? fromMaybe (“error: ChooseC mfix returned Just”)
?
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.
This is being replaced in #233 anyway, so I’mma leave it as-is.
This PR simplifies the
NonDetC
handler, and adds a couple of extra ones.