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

Add arrow-related instances #111

Merged
merged 3 commits into from
Jun 22, 2024
Merged

Add arrow-related instances #111

merged 3 commits into from
Jun 22, 2024

Conversation

mniip
Copy link
Contributor

@mniip mniip commented Jun 21, 2024

We know that:

  • Arrow = Strong + Category,
  • ArrowChoice = Choice + Strong + Category
  • ArrowLoop = Costrong + Strong + Category

The WrappedArrow class allows using profunctors classes with types that only implement base arrows instances. However since profunctors depends on base, the expectation is that anything that is a Strong Category should also be an Arrow, etc, else you can't use arrow syntax!

Hence I've added the following instances:

  • ArrowPlus p => ArrowPlus (WrappedArrow p) -- there was ArrowZero, but not ArrowPlus for some reason
  • Star
    • MonadFix f => Costrong (Star f) -- derived from Kleisli
    • Monad f => Arrow (Star f) -- derived from its strength
    • MonadPlus f => ArrowZero (Star f) -- using Alternative (we have a Monad superclass constraint anyway, hence MonadPlus)
    • MonadPlus f => ArrowPlus (Star f) -- using MonadPlus
    • Monad f => ArrowChoice (Star f) -- derived from its choice
    • Monad f => ArrowApply (Star f) -- derived from Kleisli
    • MonadFix f => ArrowLoop (Star f) -- derived from the aforementioned costrength
  • Costar
    • Comonad f => Category (Costar f) -- derived from Cokleisli
  • CofreeTraversing
    • Category p => Category (CofreeTraversing p) -- things of the form forall x. p (x ⊗ a) (x ⊗ b) (end comonads) naturally form a category
    • (Category p, Profunctor p) => Arrow (CofreeTraversing p) -- derived from its strength
    • (ArrowZero p, Profunctor p) => ArrowZero (CofreeTraversing p) -- natural for "end comonads"
    • (ArrowPlus p, Profunctor p) => ArrowPlus (CofreeTraversing p) -- natural for "end comonads" (the arrows are always in parallel)
    • (Category p, Profunctor p) => ArrowChoice (CofreeTraversing p) -- derived from its choice
  • TambaraSum
    • Strong p => Strong (TambaraSum p) -- looks asymmetric, but shouldn't be, given lawful Strong p
    • Costrong p => Costrong (TambaraSum p) -- same benign asymmetry
    • Arrow p => Arrow (TambaraSum p) -- derived from aforementioned strength
    • Arrow p => ArrowChoice (TambaraSum p) -- derived from aforementioned choice
    • ArrowZero p => ArrowZero (TambaraSum p) -- natural for "end comonads"
    • ArrowPlus p => ArrowPlus (TambaraSum p) -- natural for "end comonads"
  • PastroSum
    • Strong p => Strong (PastroSum p) -- checks out
  • Yoneda -- degenerates when Profunctor p, hence much like its other instances we just extract and proreturn
    • (Arrow p, Profunctor p) => Arrow (Yoneda p) -- derived from its strength
    • (ArrowZero p, Profunctor p) => ArrowZero (Yoneda p)
    • (ArrowPlus p, Profunctor p) => ArrowPlus (Yoneda p)
    • (ArrowChoice p, Profunctor p) => ArrowChoice (Yoneda p) -- derived from its choice
    • (ArrowApply p, Profunctor p) => ArrowApply (Yoneda p)
    • (ArrowLoop p, Profunctor p) => ArrowLoop (Yoneda p) -- derived from its costrength
  • Coyoneda -- likewise we just return and proextract
    • (Arrow p, Profunctor p) => Arrow (Coyoneda p) -- derived from its strength
    • (ArrowZero p, Profunctor p) => ArrowZero (Coyoneda p)
    • (ArrowPlus p, Profunctor p) => ArrowPlus (Coyoneda p)
    • (ArrowChoice p, Profunctor p) => ArrowChoice (Coyoneda p) -- derived from its choice
    • (ArrowApply p, Profunctor p) => ArrowApply (Coyoneda p)
    • (ArrowLoop p, Profunctor p) => ArrowLoop (Coyoneda p) -- derived from its costrength
  • Rift
    • (Strong p, Costrong q) => Costrong (Rift p q) -- checks out
    • (Choice p, Cochoice q) => Cochoice (Rift p q) -- checks out
  • Ran
    • (Strong p, Costrong q) => Costrong (Ran p q) -- same as Rift
    • (Choice p, Cochoice q) => Cochoice (Ran p q) -- same as Rift
  • Codensity
    • (Strong p, Costrong p) => Costrong (Codensity p) -- derived from Ran p p
    • (Choice p, Cochoice p) => Cochoice (Codensity p) -- derived from Ran p p
  • Day
    • (Profunctor p, Strong q) => Strong (Day p q) -- this one could alternatively be defined using p's strength, but I figured it should target the same argument as does ProfunctorMonad, also swapped is right there.
    • (Choice p, Choice q) => Choice (Day p q)

Things like Category (Pastro p) require Strong p at which point Pastro p <-> p and if you want an arrow you can just extract, so I've decided to not bother with that. Likewise with Category (FreeTraversing p).

Strong: TambaraSum, PastroSum, Day
Costrong: Star, TambaraSum, Rift, Ran, Codensity
Choice: Day
Cochoice: Rift, Ran, Codensity
Category: CofreeTraversing, Costar
Arrow: Star, CofreeTraversing, Coyoneda, TambaraSum
ArrowZero: Star, CofreeTraversing, Yoneda, Coyoneda, TambaraSum
ArrowPlus: WrappedArrow, Star, CofreeTraversing, Yoneda, Coyoneda, TambaraSum
ArrowChoice: Star, CofreeTraversing, Yoneda, Coyoneda, TambaraSum
ArrowApply: Star, Yoneda, Coyoneda
ArrowLoop: Star, Yoneda, Coyoneda, TambaraSum
Copy link
Collaborator

@RyanGlScott RyanGlScott left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Can you mention these changes in the CHANGELOG?

Comment on lines 184 to 193
-- |
-- - 'Arrow' is equivalent to 'Category'
-- && t'Data.Profunctor.Strong.Strong'.
-- - 'ArrowChoice' is equivalent to 'Category'
-- && t'Data.Profunctor.Strong.Strong' && t'Data.Profunctor.Choice.Choice'.
-- - 'ArrowLoop' is equivalent to 'Category'
-- && t'Data.Profunctor.Strong.Strong' && t'Data.Profunctor.Strong.Costrong'.
--
-- This newtype allows 'Profunctor' classes to be used with types that only
-- implement @base@'s arrow classes.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These Haddocks are now somewhat indirect, as they begin with a list of relationship between base classes and profunctor classes, and then they are followed with an explanation of what the WrappedArrow type actually is. I think it should be the other way around: first say what WrappedArrow is, and then use that to motivate the relationships between the classes.

@mniip mniip requested a review from RyanGlScott June 22, 2024 17:27
CHANGELOG.markdown Outdated Show resolved Hide resolved
@RyanGlScott RyanGlScott merged commit 05bd536 into ekmett:main Jun 22, 2024
7 checks passed
@mniip mniip deleted the arrows branch June 22, 2024 17:42
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

Successfully merging this pull request may close these issues.

None yet

2 participants