-
Notifications
You must be signed in to change notification settings - Fork 13
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
Add Cochoice instances for Joker and Star #31
base: master
Are you sure you want to change the base?
Conversation
In profunctors they specify I don't have the experience to know which instance makes more sense. |
Oh they also comment it with |
I wonder if that coincidentally works out to the same thing for stuff like |
I don't believe so. The questionable instance has the potential to loop forever. |
Would some generative tests to ensure (probable) conformity with the laws help this along? |
Yes, but also I think proofs of law conformity, and/or justifications of why these instances are appropriate (as opposed to any other instances these types might permit) would be more persuasive. |
I played around with this a little bit more today, and while unfortunately I didn't manage to find the proof of correctness we're looking for, I did manage to relate it to a more obviously lawful structure. I believe the instances below are more correct than what I had before (although for the couple of concrete instantiations I've tried it actually doesn't behave differently): class Functor f => Filterable f
where
partition :: f (Either a b) -> (f a, f b)
-- This represents an oplax monoidal functor, so the laws are analogous to those for @Apply@ expressed in terms of @zip :: (f a, f b) -> f (a, b)@
-- https://github.com/masaeedu/filterable for quickcheckable laws and more
instance Filterable m => Cochoice (Kleisli m)
where
unleft (Kleisli amb) = Kleisli $ fst . partition . amb . Left
instance (Filterable m) => Cochoice (Joker m)
where
unleft (Joker m) = Joker $ fst $ partition m These two profunctors give rise to the following combinators for using coprisms: whittle :: Filterable f => Coprism s t a b -> f b -> f t
whittle p f = runJoker $ p $ Joker $ f
speculate :: Filterable f => Coprism s t a b -> (a -> f b) -> s -> f t
speculate = dimap Kleisli runKleisli Here are a few instances of instance Filterable []
where
partition [] = ([], [])
partition (Left x : xs) = first (x :) $ partition xs
partition (Right x : xs) = second (x :) $ partition xs
instance Filterable Maybe
where
partition Nothing = (Nothing, Nothing)
partition (Just (Left a)) = (Just a, Nothing)
partition (Just (Right b)) = (Nothing, Just b)
instance Ord k => Filterable (Map k)
where
partition = foldrWithKey (\k -> either (first . insert k) (second . insert k)) (empty, empty) Here is what using everything together looks like: https://github.com/masaeedu/co-optics/blob/3f0e51cbc3bab9d94a86ead63352fe1a04f211c8/src/Main.hs To prove this is correct I need to start from the assumption that |
These should help with the long standing problem of how to make "failable"
optics. If your profunctor supports a
Cochoice
instance, you can simplyapply a Prism backwards to it.
This lets you "demote" e.g. a:
to a:
by running the
_Right
prism backwards.