bifunctors
bifunctors copied to clipboard
Added instances of Semigroup, Monoid; Bounded, Enum, Ix; and Storable where appropriate
@ekmett, I'd like to get your opinion on the Semigroup
instances for Biff
and Tannen
since they are bifunctors
' variants of Compose
from Data.Functor.Compose
, and that you had expressed reservations about a Semigroup (f (g a)) => Semigroup (Compose f g a)
instance here.
I think in light of the objections raised in base
, the same objections hold here. If we supply instances for Eq
, Show
, Read
, Ord
that they should use Data.Functor.Classes
via transformers-compat
/ transformers
on older GHCs and base
on GHC 8+ and leave off things like Semigroup
for the same reasons given there.
@duairc As far as Monoid
goes... perhaps you'd find a typeclass like Bialternative
useful?
module Data.Bialternative where
import Control.Applicative
import Data.Biapplicative
import Data.Bifunctor.Biff
import Data.Bifunctor.Clown
import Data.Bifunctor.Flip
import Data.Bifunctor.Joker
import Data.Bifunctor.Product
import Data.Bifunctor.Tannen
import Data.Bifunctor.Wrapped
-- | A monoid on applicative 'Bifunctor's.
--
-- If defined, 'bisome' and 'bimany' should be the least solutions
-- of the equations:
--
-- * @'bisome' v = 'bimap' (:) (:) v '<<*>>' 'bimany' v@
--
-- * @'bimany' v = 'bisome' v '<<|>>' 'bipure' [] []@
class Biapplicative f => Bialternative f where
-- | The identity of '<<|>>'
biempty :: f a b
-- | An associative binary operation
(<<|>>) :: f a b -> f a b -> f a b
-- | One or more.
bisome :: f a b -> f [a] [b]
bisome v = bisome_v
where
bimany_v = bisome_v <<|>> bipure [] []
bisome_v = (bimap (:) (:) v) <<*>> bimany_v
-- | Zero or more.
bimany :: f a b -> f [a] [b]
bimany v = bimany_v
where
bimany_v = bisome_v <<|>> bipure [] []
bisome_v = (bimap (:) (:) v) <<*>> bimany_v
instance (Biapplicative p, Alternative f, Alternative g) => Bialternative (Biff p f g) whe
re
biempty = Biff (bipure empty empty)
Biff x <<|>> Biff y = Biff (biliftA2 (<|>) (<|>) x y)
instance Alternative f => Bialternative (Clown f) where
biempty = Clown empty
Clown x <<|>> Clown y = Clown (x <|> y)
instance Bialternative p => Bialternative (Flip p) where
biempty = Flip biempty
Flip x <<|>> Flip y = Flip (x <<|>> y)
instance Alternative f => Bialternative (Joker f) where
biempty = Joker empty
Joker x <<|>> Joker y = Joker (x <|> y)
instance (Bialternative f, Bialternative g) => Bialternative (Product f g) where
biempty = Pair biempty biempty
Pair w x <<|>> Pair y z = Pair (w <<|>> y) (x <<|>> z)
instance (Applicative f, Bialternative p) => Bialternative (Tannen f p) where
biempty = Tannen (pure biempty)
Tannen x <<|>> Tannen y = Tannen (liftA2 (<<|>>) x y)
instance Bialternative f => Bialternative (WrappedBifunctor f) where
biempty = WrapBifunctor biempty
WrapBifunctor x <<|>> WrapBifunctor y = WrapBifunctor (x <<|>> y)
This would give a Haskell98 way to combine values of * -> * -> *
-kinded types. If you wanted an analog for Semigroup
, we could also consider adding classes like Bialt
to semigroupoids
.
Nobody has shown me any good usecases for Biapplicatives, let alone Bialternatives. =(