Skip to content
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

Make Divisible unconquerable #49

Open
treeowl opened this issue May 2, 2018 · 4 comments
Open

Make Divisible unconquerable #49

treeowl opened this issue May 2, 2018 · 4 comments

Comments

@treeowl
Copy link
Contributor

treeowl commented May 2, 2018

It strikes me as quite strange and somewhat unfortunate that conquer is a method of Divisible. I really think it should be in a subclass. The fundamental idea of Divisible is it's for problems that can be handled in arbitrary pieces. The notion of a default handler looks like extra power on top of that. Here's a simple example:

newtype Flipparr a b = Fliparr {unfliparr :: b -> a}

instance Semigroup a => Divisible (Fliparr) a where
  divide f (Fliparr g) (Fliparr h) = Fliparr $ \a ->
    case f a of
      (b, c) -> g b <> h c

To get conquer, this needs a Monoid constraint.

So I think Divisible should drop conquer, and there should be a separate class for that.

@endgame
Copy link

endgame commented Jul 13, 2019

This sounds like: "??? is to Divisible as Apply is to Applicative". It feels like it should be in semigroupoids, but isn't. Similarly: "??? is to Decideable as Alt is to Alternative". If we put them here instead of in semigroupoids we can set the superclass relationships up right, too. Once #57 is done we can also define analogous operators. Maybe these classes?

class Contravariant f => Divide f where
  divide :: (a -> (b, c)) -> f b -> f c -> f a

class Divide f => Divisible f where
  conquer :: f a

class Divide f => Decide f where
  choose :: (a -> Either b c) -> f b -> f c -> f a

class (Divisible f, Decide f) => Decideable f where
  lose :: (a -> Void) -> f a

I'm pattern-matching off the semigroupoids diagram, and skipping over Plus, because we don't seem to have an equivalent to MonadPlus.

It would be great if someone who knew the maths could check over this hierarchy and make sure that none of the splits result in lawless typeclasses.

@treeowl
Copy link
Contributor Author

treeowl commented Oct 21, 2021

@ekmett, any thoughts?

@ekmett
Copy link
Owner

ekmett commented Oct 21, 2021

I'm actually exploring something similar in the hkd package, where it seems this notion of Semidivisible becomes way more common. I will admit I'm a bit uncomfortable with the explosion of names, instances, and granularity.

I went the other way with the Comonad class at one point, basically making Extend a superclass for a long time, but then anything that switched back and forth between Monad and Comonad failed to land on the nose, due to my inability to put in a matching superclass above Monad.

So my thoughts right now are that there is a tension between making a more broadly applicable class and making a class that people really can understand how to use and that matches up with what is available on the other side of the mirrored class hierarchy.

@treeowl
Copy link
Contributor Author

treeowl commented Oct 22, 2021

I think my biggest objection to conquer always being there is that when programming by types, it can just go anywhere. The same, of course, applies to mempty, while pure (usually) doesn't do that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants