-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathP1Ch08c_BiFunctorNonHask.lhs
107 lines (88 loc) · 3.83 KB
/
P1Ch08c_BiFunctorNonHask.lhs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
|Markdown version of this file: https://github.com/rpeszek/notes-milewski-ctfp-hs/wiki/N_P1Ch08c_BiFunctorNonHask
Notes about CTFP Part 1 Chapter 8. Functoriality. BiFunctor generalized to non-Hask categories.
===============================================================================================
In this note, I define more general version of bifunctor that is similar in spirit to CFunctor.
This, more general bifunctor is needed for future use (monoidal categories [N_P3Ch06c_MonoidalCats](N_P3Ch06c_MonoidalCats)).
Refs: `category-extras`, `categories` packages
> {-#LANGUAGE MultiParamTypeClasses
> , PolyKinds
> , FlexibleInstances
> #-}
> module CTNotes.P1Ch08c_BiFunctorNonHask where
> import Control.Category
> import Prelude hiding ((.), id)
> import qualified Control.Arrow as Arr
`category-extras` and `categories` define `Monoidal` in terms of more general type classes: `Associative`, `Bifunctor`,
and `HasIdentity`.
This note bundles all 3 into one and uses a less generic approach.
> class (Category r, Category t) => CBifunctor bi r t where
> bimap :: r a c -> r b d -> t (bi a b) (bi c d)
> bimap g h = first g . second h
> first :: r a c -> t (bi a b) (bi c b)
> first g = bimap g id
> second :: r b d -> t (bi a b) (bi a d)
> second = bimap id
Read `r a c` as `homset_r a c` and `t (bi a b) (bi c d)` as `homset_t (bi a b) (bi c d)`.
This definition assumes bifunctor `R x R -> T` (instead a more general functor `R x S -> T` in `category-extras`).
Also instead of using Functor constraints it simply lists first and second projections.
For simplicity, I have also omitted functional dependencies.
Some obvious example instances:
> instance {-# OVERLAPS #-} CBifunctor Either (->) ((->)) where
> bimap f _ (Left a) = Left (f a)
> bimap _ g (Right a) = Right (g a)
>
> instance {-# OVERLAPS #-} CBifunctor (,) (->) (->) where
> bimap f g ~(a,b)= (f a, g b)
(the code below (arrows) is more generic hence the use of `OVERLAPS`)
I will use this generalized version of bifunctor in the future.
`Control.Arrow`
---------------
We know (see above) that `(,)` is a bifunctor under Hask
(category based on on `(->)` morphisms). What are some other categories where
`(,)` is a bifunctor? A bunch of such categories is called arrows.
Here is the typeclass definition from the base package (quoted only):
```
class Category a => Arrow a where
arr :: (b -> c) -> a b c
(***) :: a b c -> a b' c' -> a (b,b') (c,c')
f *** g = first f >>> arr swap >>> first g >>> arr swap
where swap ~(x,y) = (y,x)
first :: a b c -> a (b,d) (c,d)
first = (*** id)
second :: a b c -> a (d,b) (d,c)
second = (id ***)
(&&&) :: a b c -> a b c' -> a b (c,c')
(&&&) = ...
```
Compare this against the above `CBifunctor`. Set
```
r = a
t = a
bi = (,)
```
Notice `first` is `first`, `second` is `second` and `bimap` is `***`.
Basically arrows can be viewed as a category that generalized `(->)` and still
allows `(,)` to be bifunctor.
> instance Arr.Arrow arr => CBifunctor (,) arr arr where
> bimap = (Arr.***)
We can ask the same question about `Either` bifunctor. Here is a bunch of categories
that keep both `(,)` and `Either` as bifunctors:
```
class Arrow a => ArrowChoice a where
(+++) :: a b c -> a b' c' -> a (Either b b') (Either c c')
f +++ g = left f >>> arr mirror >>> left g >>> arr mirror
where
mirror :: Either x y -> Either y x
mirror (Left x) = Right x
mirror (Right y) = Left y
left :: a b c -> a (Either b d) (Either c d)
left = (+++ id)
right :: a b c -> a (Either d b) (Either d c)
right = (id +++)
(|||) :: a b d -> a c d -> a (Either b c) d
(|||) = ...
```
`first` is `left`, `second` is `right` and `bimap` is now `(+++)`.
> instance Arr.ArrowChoice arr => CBifunctor Either arr arr where
> bimap = (Arr.+++)
Nice!