Proposal: Add Semigroup/Monoid instance to Data.Functor.Compose

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Proposal: Add Semigroup/Monoid instance to Data.Functor.Compose

chessai .
Data.Functor.Compose:

newtype Compose f g a = Compose { getCompose :: f (g a) }

there's clear-cut, more traditional instances if `f` and `g` are Applicative:

instance (Applicative f, Applicative g, Semigroup a) => Semigroup (Compose f g a) where
  (<>) = liftA2 (<>)

instance (Applicative f, Applicative g, Monoid a) => Monoid (Compose f g a) where
  mempty = pure mempty

There's an alternative with `QuantifiedConstraints`, but it's arguable that this is desirable:

instance (forall x. Semigroup x => Semigroup (f x), forall x. Semigroup x => Semigroup (g x), Semigroup a) => Semigroup (Compose f g a) where
  Compose x <> Compose y = Compose (x <> y)

Both to seem to fit the commonplace spirit of lifting monoids up through applicative contexts.

_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: Add Semigroup/Monoid instance to Data.Functor.Compose

David Feuer
The alternate one can be written much more simply with
FlexibleContexts instead of QuantifiedConstraints:

instance Semigroup (f (g a)) => Semigroup (Compose f g a) where
  Compose x <> Compose y = Compose (x <> y)
instance Monoid (f (g a)) => Monoid (Compose f g a) where
  mempty = Compose mempty

That strikes me as the most natural way to do it. The lifting
instances are more naturally done using this oft-proposed type:

newtype Ap f a = Ap (f a)
instance (Applicative f, Semigroup a) => Semigroup (Ap f a) where
  Ap x <> Ap y = Ap (liftA2 (<>) x y)
instance (Applicative f, Monoid a) => Monoid (Ap f a) where
  mempty = pure mempty

Now Ap (Compose f g) a will do the lifting you want.

On Fri, Nov 30, 2018 at 4:13 PM Daniel Cartwright <[hidden email]> wrote:

>
> Data.Functor.Compose:
>
> newtype Compose f g a = Compose { getCompose :: f (g a) }
>
> there's clear-cut, more traditional instances if `f` and `g` are Applicative:
>
> instance (Applicative f, Applicative g, Semigroup a) => Semigroup (Compose f g a) where
>   (<>) = liftA2 (<>)
>
> instance (Applicative f, Applicative g, Monoid a) => Monoid (Compose f g a) where
>   mempty = pure mempty
>
> There's an alternative with `QuantifiedConstraints`, but it's arguable that this is desirable:
>
> instance (forall x. Semigroup x => Semigroup (f x), forall x. Semigroup x => Semigroup (g x), Semigroup a) => Semigroup (Compose f g a) where
>   Compose x <> Compose y = Compose (x <> y)
>
> Both to seem to fit the commonplace spirit of lifting monoids up through applicative contexts.
> _______________________________________________
> Libraries mailing list
> [hidden email]
> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: Add Semigroup/Monoid instance to Data.Functor.Compose

chessai .
Yeah, the instance being defined with Ap is certainly a good way to go. We can use DerivingVia and Data.Monoid.Ap.


On Fri, Nov 30, 2018, 4:55 PM David Feuer <[hidden email] wrote:
The alternate one can be written much more simply with
FlexibleContexts instead of QuantifiedConstraints:

instance Semigroup (f (g a)) => Semigroup (Compose f g a) where
  Compose x <> Compose y = Compose (x <> y)
instance Monoid (f (g a)) => Monoid (Compose f g a) where
  mempty = Compose mempty

That strikes me as the most natural way to do it. The lifting
instances are more naturally done using this oft-proposed type:

newtype Ap f a = Ap (f a)
instance (Applicative f, Semigroup a) => Semigroup (Ap f a) where
  Ap x <> Ap y = Ap (liftA2 (<>) x y)
instance (Applicative f, Monoid a) => Monoid (Ap f a) where
  mempty = pure mempty

Now Ap (Compose f g) a will do the lifting you want.

On Fri, Nov 30, 2018 at 4:13 PM Daniel Cartwright <[hidden email]> wrote:
>
> Data.Functor.Compose:
>
> newtype Compose f g a = Compose { getCompose :: f (g a) }
>
> there's clear-cut, more traditional instances if `f` and `g` are Applicative:
>
> instance (Applicative f, Applicative g, Semigroup a) => Semigroup (Compose f g a) where
>   (<>) = liftA2 (<>)
>
> instance (Applicative f, Applicative g, Monoid a) => Monoid (Compose f g a) where
>   mempty = pure mempty
>
> There's an alternative with `QuantifiedConstraints`, but it's arguable that this is desirable:
>
> instance (forall x. Semigroup x => Semigroup (f x), forall x. Semigroup x => Semigroup (g x), Semigroup a) => Semigroup (Compose f g a) where
>   Compose x <> Compose y = Compose (x <> y)
>
> Both to seem to fit the commonplace spirit of lifting monoids up through applicative contexts.
> _______________________________________________
> Libraries mailing list
> [hidden email]
> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: Add Semigroup/Monoid instance to Data.Functor.Compose

David Feuer
I'm suggesting that the lifting instance is the *wrong one*. Lifting is Ap's job. Compose is just for composing things.

On Fri, Nov 30, 2018, 5:14 PM Daniel Cartwright <[hidden email] wrote:
Yeah, the instance being defined with Ap is certainly a good way to go. We can use DerivingVia and Data.Monoid.Ap.


On Fri, Nov 30, 2018, 4:55 PM David Feuer <[hidden email] wrote:
The alternate one can be written much more simply with
FlexibleContexts instead of QuantifiedConstraints:

instance Semigroup (f (g a)) => Semigroup (Compose f g a) where
  Compose x <> Compose y = Compose (x <> y)
instance Monoid (f (g a)) => Monoid (Compose f g a) where
  mempty = Compose mempty

That strikes me as the most natural way to do it. The lifting
instances are more naturally done using this oft-proposed type:

newtype Ap f a = Ap (f a)
instance (Applicative f, Semigroup a) => Semigroup (Ap f a) where
  Ap x <> Ap y = Ap (liftA2 (<>) x y)
instance (Applicative f, Monoid a) => Monoid (Ap f a) where
  mempty = pure mempty

Now Ap (Compose f g) a will do the lifting you want.

On Fri, Nov 30, 2018 at 4:13 PM Daniel Cartwright <[hidden email]> wrote:
>
> Data.Functor.Compose:
>
> newtype Compose f g a = Compose { getCompose :: f (g a) }
>
> there's clear-cut, more traditional instances if `f` and `g` are Applicative:
>
> instance (Applicative f, Applicative g, Semigroup a) => Semigroup (Compose f g a) where
>   (<>) = liftA2 (<>)
>
> instance (Applicative f, Applicative g, Monoid a) => Monoid (Compose f g a) where
>   mempty = pure mempty
>
> There's an alternative with `QuantifiedConstraints`, but it's arguable that this is desirable:
>
> instance (forall x. Semigroup x => Semigroup (f x), forall x. Semigroup x => Semigroup (g x), Semigroup a) => Semigroup (Compose f g a) where
>   Compose x <> Compose y = Compose (x <> y)
>
> Both to seem to fit the commonplace spirit of lifting monoids up through applicative contexts.
> _______________________________________________
> Libraries mailing list
> [hidden email]
> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: Add Semigroup/Monoid instance to Data.Functor.Compose

chessai .
Ah, yeah, I see that now, in the "natural" comment. In that case I'm not sure if I prefer the version with FlexibleContexts or QuantifiedConstraints.

On Fri, Nov 30, 2018, 5:18 PM David Feuer <[hidden email] wrote:
I'm suggesting that the lifting instance is the *wrong one*. Lifting is Ap's job. Compose is just for composing things.

On Fri, Nov 30, 2018, 5:14 PM Daniel Cartwright <[hidden email] wrote:
Yeah, the instance being defined with Ap is certainly a good way to go. We can use DerivingVia and Data.Monoid.Ap.


On Fri, Nov 30, 2018, 4:55 PM David Feuer <[hidden email] wrote:
The alternate one can be written much more simply with
FlexibleContexts instead of QuantifiedConstraints:

instance Semigroup (f (g a)) => Semigroup (Compose f g a) where
  Compose x <> Compose y = Compose (x <> y)
instance Monoid (f (g a)) => Monoid (Compose f g a) where
  mempty = Compose mempty

That strikes me as the most natural way to do it. The lifting
instances are more naturally done using this oft-proposed type:

newtype Ap f a = Ap (f a)
instance (Applicative f, Semigroup a) => Semigroup (Ap f a) where
  Ap x <> Ap y = Ap (liftA2 (<>) x y)
instance (Applicative f, Monoid a) => Monoid (Ap f a) where
  mempty = pure mempty

Now Ap (Compose f g) a will do the lifting you want.

On Fri, Nov 30, 2018 at 4:13 PM Daniel Cartwright <[hidden email]> wrote:
>
> Data.Functor.Compose:
>
> newtype Compose f g a = Compose { getCompose :: f (g a) }
>
> there's clear-cut, more traditional instances if `f` and `g` are Applicative:
>
> instance (Applicative f, Applicative g, Semigroup a) => Semigroup (Compose f g a) where
>   (<>) = liftA2 (<>)
>
> instance (Applicative f, Applicative g, Monoid a) => Monoid (Compose f g a) where
>   mempty = pure mempty
>
> There's an alternative with `QuantifiedConstraints`, but it's arguable that this is desirable:
>
> instance (forall x. Semigroup x => Semigroup (f x), forall x. Semigroup x => Semigroup (g x), Semigroup a) => Semigroup (Compose f g a) where
>   Compose x <> Compose y = Compose (x <> y)
>
> Both to seem to fit the commonplace spirit of lifting monoids up through applicative contexts.
> _______________________________________________
> Libraries mailing list
> [hidden email]
> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: Add Semigroup/Monoid instance to Data.Functor.Compose

David Feuer
The FlexibleContexts one is as general as possible. The QuantifiedConstraints one is simultaneously less general and harder to understand. I see no possible advantage.

On Fri, Nov 30, 2018, 5:25 PM Daniel Cartwright <[hidden email] wrote:
Ah, yeah, I see that now, in the "natural" comment. In that case I'm not sure if I prefer the version with FlexibleContexts or QuantifiedConstraints.

On Fri, Nov 30, 2018, 5:18 PM David Feuer <[hidden email] wrote:
I'm suggesting that the lifting instance is the *wrong one*. Lifting is Ap's job. Compose is just for composing things.

On Fri, Nov 30, 2018, 5:14 PM Daniel Cartwright <[hidden email] wrote:
Yeah, the instance being defined with Ap is certainly a good way to go. We can use DerivingVia and Data.Monoid.Ap.


On Fri, Nov 30, 2018, 4:55 PM David Feuer <[hidden email] wrote:
The alternate one can be written much more simply with
FlexibleContexts instead of QuantifiedConstraints:

instance Semigroup (f (g a)) => Semigroup (Compose f g a) where
  Compose x <> Compose y = Compose (x <> y)
instance Monoid (f (g a)) => Monoid (Compose f g a) where
  mempty = Compose mempty

That strikes me as the most natural way to do it. The lifting
instances are more naturally done using this oft-proposed type:

newtype Ap f a = Ap (f a)
instance (Applicative f, Semigroup a) => Semigroup (Ap f a) where
  Ap x <> Ap y = Ap (liftA2 (<>) x y)
instance (Applicative f, Monoid a) => Monoid (Ap f a) where
  mempty = pure mempty

Now Ap (Compose f g) a will do the lifting you want.

On Fri, Nov 30, 2018 at 4:13 PM Daniel Cartwright <[hidden email]> wrote:
>
> Data.Functor.Compose:
>
> newtype Compose f g a = Compose { getCompose :: f (g a) }
>
> there's clear-cut, more traditional instances if `f` and `g` are Applicative:
>
> instance (Applicative f, Applicative g, Semigroup a) => Semigroup (Compose f g a) where
>   (<>) = liftA2 (<>)
>
> instance (Applicative f, Applicative g, Monoid a) => Monoid (Compose f g a) where
>   mempty = pure mempty
>
> There's an alternative with `QuantifiedConstraints`, but it's arguable that this is desirable:
>
> instance (forall x. Semigroup x => Semigroup (f x), forall x. Semigroup x => Semigroup (g x), Semigroup a) => Semigroup (Compose f g a) where
>   Compose x <> Compose y = Compose (x <> y)
>
> Both to seem to fit the commonplace spirit of lifting monoids up through applicative contexts.
> _______________________________________________
> Libraries mailing list
> [hidden email]
> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries