GithubHelp home page GithubHelp logo

bifunctors's People

Contributors

alanz avatar arkeet avatar dag avatar dolio avatar duairc avatar ekmett avatar erikd avatar exitmouse avatar felixonmars avatar hvr avatar icelandjack avatar intolerable avatar lucasdicioccio avatar maxgabriel avatar moiman avatar ocharles avatar phadej avatar quasicomputational avatar quchen avatar ryanglscott avatar stiiin avatar treeowl avatar ypares avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bifunctors's Issues

Template Haskell to derive bi* instances

Would it be useful to include derivation templates for bifunctors, bifoldables and bitraversables? I benefit quite a lot from the language extensions DeriveFunctor, DeriveFoldable, DeriveTraversable, and having templates that derives their binary counterparts would remove a lot of boilerplate in code I currently develop. I'd guess I'm not the only one experiencing this, so I was wondering if this seemed reasonable to include this in the library itself.

For example something à la

data Foo a b = L a
             | R b
             | LR a b
             | None

$(derive [makeBifunctor, makeBifoldable, makeBitraversable] ''Foo)

Composing functors and a bifunctor.

I found myself needing to compose a bifunctor and a functor in a way that preserved bifunctorality, and I think that this code might be generally useful. I'm not really sold on the naming but I hope it's clear enough, especially with the type signatures; if there's a better name for this sort of thing that comes from theory or just intuition, please feel free to change it.

-- | Compose a bifunctor and two functors, one on the 'outside' (left) of the bifunctor and one on the 'inside' (right), preserving bifunctorality.
newtype HalfBicompose f p g a b = HalfBicompose { getHalfBicompose :: f (p a (g b)) }

-- | A bifunctor composed with a functor, preserving bifunctorality.
type HalfBicomposeL = HalfBicompose Identity

-- | A functor composed with a bifunctor, preserving bifunctorality.
type HalfBicomposeR f p = HalfBicompose f p Identity

instance (Bifunctor p, Functor f, Functor g) => Bifunctor (HalfBicompose f p g) where
  bimap f g = HalfBicompose . fmap (bimap f (fmap g)) . getHalfBicompose

instance (Bifunctor p, Functor f, Functor g) => Functor (HalfBicompose f p g a) where
  fmap = second

instance (Biapply p, Apply f, Apply g) => Biapply (HalfBicompose f p g) where
  HalfBicompose f <<.>> HalfBicompose a = HalfBicompose $ liftF2 (bilift2 ($) (<.>)) f a

instance (Biapplicative p, Applicative f, Applicative g) => Biapplicative (HalfBicompose f p g) where
  bipure a b = HalfBicompose $ pure (bipure a (pure b))
  HalfBicompose f <<*>> HalfBicompose a = HalfBicompose $ liftA2 (biliftA2 ($) (<*>)) f a

instance (Bifoldable p, Foldable f, Foldable g) => Bifoldable (HalfBicompose g p f) where
  bifoldMap f g = foldMap (bifoldMap f (foldMap g)) . getHalfBicompose

instance (Bifoldable p, Foldable f, Foldable g) => Foldable (HalfBicompose f p g a) where
  foldMap = bifoldMap (const mempty)

instance (Bitraversable p, Traversable f, Traversable g) => Bitraversable (HalfBicompose f p g) where
  bitraverse f g = fmap HalfBicompose . traverse (bitraverse f (traverse g)) . getHalfBicompose

instance (Bitraversable p, Traversable f, Traversable g) => Traversable (HalfBicompose f p g a) where
  traverse = bitraverse pure

fromHalfBicomposeL :: HalfBicomposeL p f a b -> p a (f b)
fromHalfBicomposeL = runIdentity . getHalfBicompose

toHalfBicomposeL :: p a (f b) -> HalfBicomposeL p f a b
toHalfBicomposeL = HalfBicompose . Identity

fromHalfBicomposeR :: (Functor f, Bifunctor p) => HalfBicomposeR f p a b -> f (p a b)
fromHalfBicomposeR = fmap (second runIdentity) . getHalfBicompose

toHalfBicomposeR :: (Functor f, Bifunctor p) => f (p a b) -> HalfBicomposeR f p a b
toHalfBicomposeR = HalfBicompose . fmap (second Identity)

halfBicomposeL2R :: (Applicative f, Bifunctor p, Traversable (p a)) => HalfBicomposeL p f a b -> HalfBicomposeR f p a b
halfBicomposeL2R = toHalfBicomposeR . sequenceA . fromHalfBicomposeL

halfBicomposeR2L :: (Traversable f, Bifunctor p, Applicative (p a)) => HalfBicomposeR f p a b -> HalfBicomposeL p f a b
halfBicomposeR2L = toHalfBicomposeL . sequenceA . fromHalfBicomposeR

(Bi?)Compose

Section 3 of Constructing Applicative Functors describes defining ZipList as a fixed point of the composition of Maybe ∘ ×. If we have a composition of a functor and a bifunctor

newtype (f · g) a b = C (f (g a b))

we can define ZipList as Fix (Maybe · (,))

type ZipList = Fix (Maybe · (,))

pattern Nil :: ZipList a
pattern Nil = In (C Nothing)

infixr 5 :::
pattern (:::) :: a -> ZipList a -> ZipList a
pattern a:::as = In (C (Just (as, a)))

Add functions from Biff to Sum/Product/Lift

Are any of these (/ inverses) useful

toSum :: Biff Either f g a a -> Sum f g a
toSum (Biff (Left  fa)) = InL fa
toSum (Biff (Right ga)) = InR ga

toProduct :: Biff (,) f g a a -> Product f g a
toProduct (Biff (fa, ga)) = Pair fa ga

-- transformers
toLift :: Biff Either Identity g a a -> Lift g a
toLift (Biff (Left (Identity a))) = Pure  a
toLift (Biff (Right ga))          = Other ga

Consolidation?

Adding BifunctorComonad carries a price. We don't have a good place to put the BifunctorComonad instance for Tannen it'd have to live as an orphan in comonad or cause us to pick up a comonad dependency.

On the other hand we have a Cayley construction in profunctors, which does exactly the same thing and works just fine because profunctors has a comonad dependency.

We could add a comonad dependency to this package, which might cause some hue and cry over the fact that Data.Bifunctor moved into base.

Or we could try to consolidate more of these little packages into a bigger package and kill the issue with cycles, and avoid orphan instances all in one go.

The issue is that in the profunctors world the free/cofree versions of each construction really should live with the class in question as they are always available, while here, we have a bit more freedom.

Change order of Data.Bifunctor.Fix

The order of Fix is unfortunate, it means that given a standard base functor

data FList a list = FNil | FCons a list 

instance Bifunctor FList where
  bimap :: (a -> a') -> (list -> list') -> (FList a list -> FList a' list')
  bimap f g = \case
    FNil      -> FNil
    FCons a b -> FCons (f a) (g b)

instance Bifoldable FList where
  bifoldMap :: Monoid m => (a -> m) -> (list -> m) -> (FList a list -> m)
  bifoldMap f g = \case
    FNil      -> mempty
    FCons a b -> f a <> g b

we get an unexpected order of elements

type List = Fix FList

pattern Nil :: List a
pattern Nil = In FNil

infixr 5 :::
pattern (:::) :: a -> List a -> List a
pattern a:::as = In (FCons as a)

>>> toList (1:::2:::3:::4:::Nil)
[4,3,2,1]

I had the same problems with defining newtype ZipList a = ZL (Fix (Tannen Maybe (,)) from #57 where I need to wrap it in Reverse to get the Foldable I want.


if it were the other way round like The Essence of the Iterator Pattern

data Fix' p a = In' { out' :: p a (Fix' p a) }

we would get the right ordering and the argument of fold fits the shape of an algebra

type Alg f a = f a -> a

fold :: Bifunctor f => Alg (f a) b -> (Fix' f a -> b)
fold f = f . second . (fold f) . out'

deriveBifunctor fails on Compose

I can currently write the following:

data Hello x a = Hello { foo :: Maybe [a] }
deriveBifunctor ''Hello

But I cannot write the following equivalent definition:

data Hello x a = Hello { foo :: Compose Maybe [] a }
deriveBifunctor ''Helo

It is rejected with:

src/Language/Haskell/GHC/Token.hs:18:1: error:
    • Couldn't match kind ‘* -> *’ with ‘*’
      When matching types
        p0 :: * -> * -> *
        Compose Maybe :: (* -> *) -> * -> *
      Expected type: p0 b0 c
        Actual type: Compose Maybe [] c
    • In the third argument of ‘Data.Bifunctor.bimap’, namely
        ‘_arg1_aT2x’
      In the first argument of ‘Hello’, namely
        ‘(((Data.Bifunctor.bimap (\ x_aT2D -> x_aT2D)) g_aT2o) _arg1_aT2x)’
      In the expression:
        Hello
          (((Data.Bifunctor.bimap (\ x_aT2D -> x_aT2D)) g_aT2o) _arg1_aT2x)

Could this be made to work?

deriveBifoldable generates an unused-variable

With

newtype XY a b= XY { getResp :: Either X (Y a b) }
  deriving (Show, Functor, Foldable)

we get

    TH.deriveBifoldable ''XY
  ======>
    instance Bifoldable XY where
      bifoldr
        = \ f_asLl g_asLm z_asLn value_asLo
            -> ((((bifunctors-5.5.9:Data.Bifunctor.TH.Internal.bifoldrConst
                     (case value_asLo of {
                        XY _arg1_asMt
                          -> ((\ n1_asMn n2_asMo
                                 -> (((bifoldr (\ n1_asMp n2_asMq -> n2_asMq))
                                        (\ n1_asMr n2_asMs
                                           -> (((bifoldr f_asLl) g_asLm) n2_asMs) n1_asMr))
                                       n2_asMo)
                                      n1_asMn)
                                _arg1_asMt)
                               z_asLn }))
                    f_asLl)
                   g_asLm)
                  z_asLn)
                 value_asLo
      bifoldMap
        = \ f_asMv g_asMw value_asMy
            -> (((bifunctors-5.5.9:Data.Bifunctor.TH.Internal.bifoldMapConst
                    (case value_asMy of {
                       XY _arg1_asNy
                         -> ((bifoldMap (\ n_asNx -> mempty)) ((bifoldMap f_asMv) g_asMw))
                              _arg1_asNy }))
                   f_asMv)
                  g_asMw)
                 value_asMy

and two warnings:

warning: [-Wunused-matches]
    Defined but not used: ‘n1’
    |
304 | TH.deriveBifoldable    ''XY
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

warning: [-Wunused-matches]
    Defined but not used: ‘n’
    |
304 | TH.deriveBifoldable    ''XY
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The offenses are (\ n1_asMp n2_asMq -> n2_asMq) and (\ n_asNx -> mempty), I think.

We're unfortunately handling this by disabling that warning in the module, for now.

Thanks!

bifunctor-classes-compat and old bifunctors

It's easy to have an install plan with old bifunctors and (new) bifunctor-classes-compat thus having two Bifunctor definitions lying around for GHC-8.0 and older.

I don't recall how we have dealt with such issues previously, or did we at all?

EDIT: real world example:

Imagine I change assoc to depend on bifunctor-classes-compat: every current user of it (e.g. these) will break, as these would define Bifunctor These for bifunctors.Bifunctor.

Does this mean, that to do that change in assoc, I should make a major version bump, so the downstream would need to react? I guess so, unless there's some trick which escapes me now.

Category cat => Monoid (Join cat a)

instance Category cat => Semigroup (Join cat a) where
  Join f <> Join g = Join (f . g)

instance Category cat => Monoid (Join cat a) where
  mempty  = Join id
  mappend = (<>)

This allows deriving Monoid (Kleisli m a a) and

newtype Endo a = Endo { appEndo :: Join (->) a }
  deriving 
    (Semigroup, Monoid)

Add function that map the same function on both parameters

I often use something like this:

bothmap :: Bifunctor f => (a -> b) -> f a a -> f b b
bothmap f = bimap f f

I typically use it with pairs where function f is a lambda expression and I'm lazy to bind it to a name. It would be nice to have it in the library.

bifunctors-5.4 contains breaking change

@phadej discovered this via ekmett/pointed#17 (comment)

There's two options from here on:

  • A) Follow-up quickly with a bifunctors-5.4.0.1 release which fixes this by marking the affected modules trustworthy and restore their previous SafeHaskell status (and then declare bifunctors-5.4 a broken release)

or the more messy

  • B) Consider this a desired breaking change and keep those modules unsafe, which means retrofitting bifunctors < 5.4 upper bounds in some places.

GHC-8.0 compatibility regarding template-haskell

ghc-8.0.0.20160109 says:

[ 1 of 15] Compiling Paths_bifunctors ( dist/build/autogen/Paths_bifunctors.hs, dist/build/Paths_bifunctors.o )
[ 2 of 15] Compiling Data.Bifunctor.TH.Internal ( src/Data/Bifunctor/TH/Internal.hs, dist/build/Data/Bifunctor/TH/Internal.o )

src/Data/Bifunctor/TH/Internal.hs:221:19: error:
    Not in scope: data constructor ‘FamilyD’
    Perhaps you meant ‘FamilyI’ (imported from Language.Haskell.TH.Syntax)

Doc typos

In the RHS of the composition law stated in Data.Bitraversable: that should be bitraverse, not traverse, right?

Data.Bifunctor.Flip's description duplicates Data.Bifunctor.Clown's; I -think- that's wrong, but if I squint, the phrasing makes cryptic sense for both of them. I'd probably change Flip to "Swap the arguments to a Bifunctor".

Bicayley

Does this belong anywhere? Just as we have Cayley

newtype Cayley f p a b = Cayley (f (p a b))

instance (Applicative f, Category p) => Category (Cayley f p) where

we can have

newtype Bicayley f p q a b = Bicayley (f (p a b) (q a b))

instance (Biapplicative f, Category p, Category q) => Category (Bicayley f p q) where
  id = Bicayley (bipure id id)
  Bicayley f . Bicayley g = Bicayley (biliftA2 (.) (.) f g)

No use cases personally.

Add Lift instances for Template Haskell

In the spirit of "If we can, then we should". I think most of them can just be derived. Yoneda and Coyoneda need to be written by hand, but it's no big deal. I'm pretty sure Day is a no-go.

WrappedBifunctor should have an Applicative instance

instance (Biapplicative p, Monoid a) => Applicative (WrappedBifunctor p a) where
  pure a = WrapBifunctor (bipure mempty a)
  {-# inline pure #-}
  liftA2 f (WrapBifunctor xs) (WrapBifunctor ys) = WrapBifunctor $ biliftA2 mappend f xs ys
  {-# inline liftA2 #-}

Deriving Bifunctor falls over on sufficiently higher-rank field types

It turns out that Data.Bifunctor.TH suffers from the same bug that caused GHC#17880. Here is a minimal demonstration of the bug:

{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TemplateHaskell #-}
module Bug where

import Data.Bifunctor.TH

data T a b = MkT (forall c. c -> (forall d. a -> d) -> a)
$(deriveBifunctor ''T)

This should compile, but fails with the following error:

Bug.hs:8:3: error:
    • Couldn't match type ‘forall d1. a -> d1’ with ‘a -> p0’
      Expected type: c1 -> (a -> p0) -> a
        Actual type: c1 -> (forall d. a -> d) -> a
    • In the first argument of ‘\ x_ajqV b_ajqW
                                  -> (\ x_ajqX b_ajqY
                                        -> f_ajqR
                                             (x_ajqX
                                                ((\ x_ajqZ b_ajr0
                                                    -> (\ x_ajr1 -> x_ajr1)
                                                         (x_ajqZ (f_ajqR b_ajr0)))
                                                   b_ajqY)))
                                       (x_ajqV ((\ x_ajr2 -> x_ajr2) b_ajqW))’, namely
        ‘_arg1_ajqU’
      In the first argument of ‘MkT’, namely
        ‘((\ x_ajqV b_ajqW
             -> (\ x_ajqX b_ajqY
                   -> f_ajqR
                        (x_ajqX
                           ((\ x_ajqZ b_ajr0 -> (\ x_ajr1 -> x_ajr1) (x_ajqZ (f_ajqR b_ajr0)))
                              b_ajqY)))
                  (x_ajqV ((\ x_ajr2 -> x_ajr2) b_ajqW)))
            _arg1_ajqU)’
      In the expression:
        MkT
          ((\ x_ajqV b_ajqW
              -> (\ x_ajqX b_ajqY
                    -> f_ajqR
                         (x_ajqX
                            ((\ x_ajqZ b_ajr0 -> (\ x_ajr1 -> x_ajr1) (x_ajqZ (f_ajqR b_ajr0)))
                               b_ajqY)))
                   (x_ajqV ((\ x_ajr2 -> x_ajr2) b_ajqW)))
             _arg1_ajqU)
    • Relevant bindings include
        _arg1_ajqU :: forall c. c -> (forall d. a -> d) -> a
          (bound at Bug.hs:8:3)
        value_ajqT :: T a c (bound at Bug.hs:8:3)
        f_ajqR :: a -> b (bound at Bug.hs:8:3)
        bimap :: (a -> b) -> (c -> d) -> T a c -> T b d
          (bound at Bug.hs:8:3)
  |
8 | $(deriveBifunctor ''T)
  |   ^^^^^^^^^^^^^^^^^^^

GHC has fixed this bug upstream, and it should be possible to apply a similar fix in Data.Bifunctor.TH.

Viewing `Bifunctor` as `Functor`.

I think it'd be useful to have the possibility of viewing a Bifunctor as a standard Functor in each its type argument. I suggest something like:

-- | Views a bifunctor as a functor in its first type argument.
newtype AsFunctor1 p b a = AsFunctor1 { getAsFunctor1 :: p a b }
instance Bifunctor p => Functor (AsFunctor1 p b) where
    fmap f = AsFunctor1 . first f . getAsFunctor1
    {-# INLINE fmap #-}

-- | Views a bifunctor as a functor in its second type argument.
newtype AsFunctor2 p a b = AsFunctor2 { getAsFunctor2 :: p a b }
instance Bifunctor p => Functor (AsFunctor2 p a) where
    fmap f = AsFunctor2 . second f . getAsFunctor2
    {-# INLINE fmap #-}

Deriving Bifunctor et al. chokes on type families with an appropriate return kind

Consider the following setup:

{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
module Bug where

import Data.Bifunctor
import Data.Bifunctor.TH
import Data.Kind

type family F :: Type -> Type -> Type
type instance F = Either
newtype T a b = MkT (F a b)

One can derive a Bifunctor instance for T using GeneralizedNewtypeDeriving:

deriving newtype instance Bifunctor T

Trying to use Template Haskell to accomplish the same thing, however, fails:

$(deriveBifunctor ''T)
Bug.hs:1:1: error:
    Exception when trying to run compile-time code:
      Constructor ‘MkT‘ must only use its last two type variable(s) within the last two argument(s) of a data type
CallStack (from HasCallStack):
  error, called at src/Data/Bifunctor/TH.hs:903:32 in bifunctors-5.5.7-382d87a82a5fe85a191a6a3943a4d9c453af2598fed3436d948a78b02f584473:Data.Bifunctor.TH
    Code: deriveBifunctor ''T
  |
1 | {-# LANGUAGE DerivingStrategies #-}
  | ^

The issue is that deriveBifunctor is too conservative: it bails out if the last type variables (a/b) occur as an argument to any type family whatsoever. Although F is a type family, its use in MkT is benign, since the type F a b oversaturates F (it has zero type variable binders). deriveBifunctor should take the number of type variable binders a type family has into account so as to permit the program above.

Superclasses from base

Is there a reason why Bifunctor, Bifoldable and Bitraversable aren't subclasses of Functor, Foldable and Traversable? fmap and right should be the same by parametricity, and I would personally be very surprised to see bifoldMap (const mempty) and foldMap or bitraverse pure and traverse produce different results.

`bifunctors` claims to be compatible with `base >= 4` incorrectly

(Data.Monoid exports <> starting with base-4.5.0.0)

[11 of 12] Compiling Data.Bifunctor.Product ( src/Data/Bifunctor/Product.hs, dist/dist-sandbox-43547874/build/Data/Bifunctor/Product.o )

src/Data/Bifunctor/Product.hs:22:37:
    Module `Data.Monoid' does not export `(<>)'
Failed to install bifunctors-4.1.0.1

Depend on assoc for instances

assoc provides Bifunctor p => Swap p and Assoc p type-classes.

Currently assoc depends on bifunctors to provide instances for Flip, Biff etc types defined in bifunctors.

But now we have a light compatibility package bifunctor-classes-compat.

So I propose a following dependency rearrangement:

  • assoc depends on bifunctor-classes-compat and provides type-classes and instances for things in base
  • bifunctors depends on assoc to provide Swap and Assoc instances for extra bifunctors defined here
  • e.g. lens is not really affected, as it still depends on both assoc and bifunctors. lens defines Wrapped instance for Biff, Clown ... etc, otherwise it could drop (at least direct) bifunctors dependency as well)
  • but e.g. these could drop bifunctors dependency as it only needs Bifunctor type-class and type-classes defined in assoc package.

This will be breaking change in assoc but only a minor change in bifunctors.

How does this sound?

bifunctors-5.3 does not compile with GHC 8.0.1-rc1

Configuring bifunctors-5.3...
Flags chosen: tagged=True, semigroups=True
Dependency QuickCheck -any: using QuickCheck-2.8.2
Dependency base -any: using base-4.9.0.0
Dependency base-orphans -any: using base-orphans-0.5.3
Dependency bifunctors -any: using bifunctors-5.3
Dependency comonad -any: using comonad-5
Dependency containers -any: using containers-0.5.7.1
Dependency hspec -any: using hspec-2.2.3
Dependency semigroups >=0.8.3.1 && <1: using semigroups-0.18.1
Dependency tagged >=0.7.3 && <1: using tagged-0.8.3
Dependency template-haskell -any: using template-haskell-2.11.0.0
Dependency transformers -any: using transformers-0.5.1.0
Dependency transformers-compat -any: using transformers-compat-0.5.1.4
Using Cabal-1.23.1.0 compiled by ghc-8.0
Using compiler: ghc-8.0.0.20160204
[...]
Building bifunctors-5.3...
Preprocessing library bifunctors-5.3...
[ 1 of 17] Compiling Paths_bifunctors ( dist/build/autogen/Paths_bifunctors.hs, dist/build/Paths_bifunctors.o )
[ 2 of 17] Compiling Data.Bifunctor.TH.Internal ( src/Data/Bifunctor/TH/Internal.hs, dist/build/Data/Bifunctor/TH/Internal.o )
[ 3 of 17] Compiling Data.Bifunctor.TH ( src/Data/Bifunctor/TH.hs, dist/build/Data/Bifunctor/TH.o )
[ 4 of 17] Compiling Data.Bifunctor.Functor ( src/Data/Bifunctor/Functor.hs, dist/build/Data/Bifunctor/Functor.o )
[ 5 of 17] Compiling Data.Bifoldable  ( src/Data/Bifoldable.hs, dist/build/Data/Bifoldable.o )
[ 6 of 17] Compiling Data.Bitraversable ( src/Data/Bitraversable.hs, dist/build/Data/Bitraversable.o )

src/Data/Bitraversable.hs:212:10: error:
    • No instance for (Bifunctor (K1 i))
        arising from the superclasses of an instance declaration
    • In the instance declaration for ‘Bitraversable (K1 i)’

Use of source-repository-packages/cabal.project in CI

I recently committed some fixes to another branch in an attempt to fix the CI for bifunctors. I haven't pushed to master yet, however, because it does a couple of opinionated things:

  1. Instead of using submodules, like in the master branch of distributive, it vendors in the comonad library using a source-repository-package in the cabal.project file. See here.
  2. Speaking of which, I'm using a cabal.project file. bifunctors used to have one, but @ekmett appears to have removed it in bc5d8e8 for reasons that aren't clear to me.

In any case, let me briefly explain why I favor (1) and (2) above:

  1. Using source-repository-package allows vendored libraries to be saved in cabal's store (using cabal-instal-3.4 or later), which means that you don't have to constantly rebuild them. More critically, it also means that vendored libraries can be cached in CI, so it will save quite a bit of CI time in the long run.
  2. Having a cabal.project file makes it so that I can check out the bifunctors repo within the context of another project with a cabal.project file and not have the latter cabal.project file clobber it. This is important for my workflows, as I manage bifunctors within another repo.

@ekmett: I'm raising this issue because I don't want to step on your toes when you're developing your libraries. Let me know your preferences and I can find a way to make both of us happy.

Type-level Uncurry?

I'm writing some code and I've run into the need to have a type like this:

newtype Uncurry f (p :: (k, l)) = Uncurry (forall a b. p ~ '(,) a b => f a b)

I've tried to see if there exists a type like that in any popular packages, but there doesn't seem to be. There may be under a different name though. But assuming there isn't, would you be interested in adding such a type to bifunctors? It seems like a reasonable place to put such a type. If you're interested, I can do up a pull request with appropriate instances and everything. If you have some guidance about what module you'd like to put it in (i.e., what you'd call that module) that would help too, because I'm not really sure what to call it. Thanks!

GHC 7.10 and Data.Bifunctor

We get many ambiguous imports for Data.Bifunctor when building packages (e.g. free).

What is the story for this?

  • leave out Data.Bifunctor from this package and use it from base instead
  • use PackageImports everywhere?

extract first or second element

With bifunctors one can map over each element, but how about just extracting an element? A generalization of fst and snd (of a tuple). Maybe something like this already exists with lens?

Kind mismatch in derived instances

data Bar a b where
  Bar :: b -> Bar True b

data Foo b c where
  Foo :: Bar x c -> Foo b c

deriveBifunctor ''Foo
    • Couldn't match kind ‘Bool’ with ‘*’
      When matching types
        p0 :: * -> * -> *
        Bar :: Bool -> * -> *
      Expected: Bar x d
        Actual: p0 b0 d
    • In the first argument of ‘Foo’, namely
        ‘(((bimap (\ _n_a7u1C -> _n_a7u1C)) g_a7u1v) _arg1_a7u1B)’
      In the expression:
        Foo (((bimap (\ _n_a7u1C -> _n_a7u1C)) g_a7u1v) _arg1_a7u1B)
      In a case alternative:
          Foo _arg1_a7u1B
            -> Foo (((bimap (\ _n_a7u1C -> _n_a7u1C)) g_a7u1v) _arg1_a7u1B)
    |
419 | deriveBifunctor ''Foo
    | ^^^^^^^^^^^^^^^^^^^^^

The derived instance shouldn't be using bimap here but rather just fmap

BiPointed type class

Bifunctors have BiApply, but lack BiPointed. like

class BiPointed f where
    bipoint :: a -> b -> f a b

There aren't many types in base which can benefit from it (I can't actually imagine anything but (,)), but it might be useful for people using bifunctors package.

Instances for single-constructor types aren't lazy

The instances of Bifunctor and Biapply aren't as lazy as they could be for single-constructor types. For example, comparing (Control.Arrow.***) and Data.Bifunctor.bimap:

> (Control.Arrow.***) (const 0) (const 1) undefined :: (Int,Int)
(0,1)
> Data.Bifunctor.bimap (const 0) (const 1) undefined :: (Int,Int)
*** Exception: Prelude.undefined

The Bifunctor instances for the various tuple types and Const should be using irrefutable patterns. Likewise for the Biapply (,) instance.

Make semigroupoids depend on bifunctors, not the other way around

This is a bit of an unusual request, but would it be feasible to remove bifunctors' dependency on semigroupoids and move the affected instances to semigroupoids instead? The reason I want this is because as of GHC 7.10, Data.Bifunctor is in base, so anyone who wants to backport Bifunctor support for older versions of GHC will need to depend on bifunctors. This brings in a whole host of unneeded dependencies (e.g., contravariant, StateVar, distributive, etc.) just to be able to use Data.Bifunctor. Reversing the order of the dependencies would lighten the installation burden for users of older versions of GHC.

Drop support for pre-8.0 versions of GHC in the `5` branch

This originally came out of a discussion in ekmett/semigroupoids#130, which discusses some additional changes to bifunctors needed for the benefit of a future foldable1-classes-compat package. In particular, we wish to split out the Data.Bifunctor, Data.Bifoldable, and Data.Bitraversable modules from bifunctors into a more minimal bifunctor-classes-compat package with fewer dependencies, and then have bifunctors re-export these modules. There is one catch: cabal's reexported-modules feature only supports GHC 7.10 and later. As a result, we have decided that this is as good of a time as any to drop pre-8.0 support in bifunctors, which is perhaps overdue as it is.

Note that this really only matters for the 5 branch of bifunctors. The main branch only support GHC 8.6 and later, so none of these changes would apply to that branch.

bisequence

From here, I don't know if it requires unsafe

biSequence :: (Biapplicative p, T.Traversable t) => t (p a b) -> p (t a) (t b)
biSequence = bimap (fmap somethingCoerce) (fmap somethingCoerce)
             . unCollapse
             . T.sequenceA
             . fmap (Collapse . bimap Something Something)

Bitraverse laws bug

It looks like on 391c314#L283 there's a t . missing on the right hand side of that law.

Hackage says

naturality
bitraverse (t . f) (t . g) ≡ t . bitraverse f g for every applicative transformation t

GHC 8 cannot build tests for 5.2

Preprocessing test suite 'bifunctors-spec' for bifunctors-5.2...
[1 of 2] Compiling BifunctorSpec    ( tests/BifunctorSpec.hs, dist/build/bifunctors-spec/bifunctors-spec-tmp/BifunctorSpec.dyn_o )

tests/BifunctorSpec.hs:1:1: error:
    Exception when trying to run compile-time code:
      src/Data/Bifunctor/TH.hs:(341,1)-(356,70): Non-exhaustive patterns in function makeBiFunForCon

    Code: deriveBifoldable ''StrangeGADT

I see there are closed issues about GHC 8, so if this has already been fixed feel free to close this issue and shout at me!

Eq1, Show1, … instances for Data.Bifunctor.Fix

Do they make sense? I only have patience to define Eq1

instance (Biapplicative f, Bifoldable f) => Eq1 (Fix f) where 
  liftEq :: (a -> a' -> Bool) -> (Fix f a -> Fix f a' -> Bool)
  liftEq (===) (In x) (In y) = biand z where
    z :: f Bool Bool
    z = biliftA2 (liftEq (===)) (===) x y

Applicative Tannen

I forgot if I've brought this up before, should this instance exist?

instance (Applicative f, Biapplicative bi, Monoid a) => Applicative (Tannen f bi a) where
 pure :: b -> Tannen f bi a b
 pure b = Tannen do
  pure (bipure mempty b)

 liftA2 :: (b1 -> b2 -> b3) -> (Tannen f bi a b1 -> Tannen f bi a b2 -> Tannen f bi a b3)
 liftA2 (·) (Tannen as) (Tannen bs) = Tannen do
  liftA2 (biliftA2 (<>) (·)) as bs

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.