Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where is the bifunctor for functions in haskell?

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

enter image description here


UPDATE

enter image description here


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

like image 294
srghma Avatar asked Jul 18 '18 08:07

srghma


2 Answers

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

    • for objects: datatype constructor. Kind Type -> Type, mapping-association a ⟼ f a.
    • for morphisms: fmap. Type: (a -> b) -> (f a -> f b).
  • Bifunctor

    • for objects: datatype constructor. Kind Type×Type -> Type, or curried Type -> Type -> Type, mapping-association a ⟼ b ⟼ p a b.
    • for morphisms: 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.

like image 72
leftaroundabout Avatar answered Nov 11 '22 06:11

leftaroundabout


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
like image 39
chepner Avatar answered Nov 11 '22 07:11

chepner