I can't find bifunctor analog of fmap.
Explanation:
Functor for objects - datatype constructor. Type -
a -> f a
Functor for functions - fmap
. Type - (a -> b) -> (fa -> fb)
Bifunctor for objects - result of bimap f g
, where f :: (a -> a')
, g :: (b -> b')
. Type - p a b -> p a' b'
Bifunctor for functions - ?. Type - p (a -> b) (c -> d) -> p (a' -> b') (c' -> d')
Here is why I think bifunctor have such type (am I right?) with some example
UPDATE
UPDATE2
p (a -> b) (c -> d) -> p (a' -> b') (c' -> d')
in the image above is morphism from bifunctor to bifunctor and also profunctor (because all functions are profunctors)
Summary:
I've thought p (a -> b) (c -> d) -> p (a' -> b') (c' -> d')
is bifunctor for functions, but it's not. Bifunctor for morphisms is bimap. Type: (a -> b) -> (α -> β) -> p a α -> p b β.
I've thought p (a -> b) (c -> d) -> p (a' -> b') (c' -> d')
is something unusual, but it's not, it's just function
Functor for objects - datatype constructor. Type -
a -> f a
Functor for functions -
fmap
. Type -(a -> b) -> (fa -> fb)
Although this makes broadly sense, it is important to realise that the arrows above have three different meanings.
Functor for objects - datatype constructor. Type -
a ⟼ f a
Functor for functions -
fmap
. Type -(a ⟿ b) ⟶ (f a ⟿ f b)
where
⟼
is a type-level “maps-to symbol” that associates the type a
with a type f a
. This does not have anything to do with value-level functions whose domain is a
and codomain f a
. (Those are found in applicatives/monads, but that's a different story.)⟿
is a type constructor for some morphism. In the Hask category, those morphisms happen to be Haskell functions, but that's just a special case.⟶
is an actual function-type constructor.You may for now forget about the distinction between the latter two, but ⟼
and ⟶
are really quite different conceptually†. Basically, ⟼
is like the arrow you write in a lambda
Maybe :: Type -> Type
Maybe = \a ⟼ Maybe a
whereas ⟶
is just a way to express that you're abstracting over function-things.
Another related thing that might not be clear is that the objects you're talking about are Haskell types. Not values (as OO objects are).
So, I would phrase the listing you gave above thus:
Functor
Type -> Type
, mapping-association a ⟼ f a
.fmap
. Type: (a -> b) -> (f a -> f b)
.Bifunctor
Type×Type -> Type
, or curried Type -> Type -> Type
, mapping-association a ⟼ b ⟼ p a b
.bimap
. Type: (a -> b) -> (α -> β) -> p a α -> p b β
.†Actually, Haskell does not have ⟼
or what you wrote with a -> f a
. This would be a type-level lambda, but type-level functions can actually only be expressed as type families, i.e. the closest you could get to expressing a ⟼ f a
is type instance Functored a = f a
.
You don't need a Bifunctor
instance for (->)
, just (,)
:
b1 :: a -> Id a
b2 :: a -> Id2 a
-- instance Bifunctor (,) where
-- bimap f g (x, y) = (f x, g y)
f :: (Int, Float) -> (Id Int, Id2 Float)
f = bimap b1 b2
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With