diff --git a/docs/typeclasses.md b/docs/typeclasses.md
index 85a4d32f69..a4ec759e94 100644
--- a/docs/typeclasses.md
+++ b/docs/typeclasses.md
@@ -1,10 +1,12 @@
# Type Classes
+
Type classes are a powerful tool used in functional programming to enable ad-hoc polymorphism, more commonly
known as overloading. Where many object-oriented languages leverage subtyping for polymorphic code, functional
programming tends towards a combination of parametric polymorphism (think type parameters, like Java generics)
and ad-hoc polymorphism.
## Example: collapsing a list
+
The following code snippets show code that sums a list of integers, concatenates a list of strings, and unions a list
of sets.
@@ -42,6 +44,7 @@ def combineAll[A](list: List[A], m: Monoid[A]): A = list.foldRight(m.empty)(m.co
```
## Type classes vs. subtyping
+
The definition above takes an actual monoid argument instead of doing the usual object-oriented practice of using
subtype constraints.
@@ -156,6 +159,7 @@ combineAll(List(Paired(1, "hello"), Paired(2, " "), Paired(3, "world")))
```
## A note on syntax
+
In many cases, including the `combineAll` function above, the implicit arguments can be written with syntactic sugar.
```scala mdoc:compile-only
@@ -227,36 +231,30 @@ You can find out more about law testing [here](typeclasses/lawtesting.md).
## Type classes in Cats
-
-From [cats-infographic by @tpolecat](https://github.com/tpolecat/cats-infographic).
-
+
+From [cats-infographic by @tpolecat, updated by @ShapelessCat](https://github.com/ShapelessCat/cats-infographic).
## Incomplete type class instances in cats
Originally from [@hobwekiva](https://gist.github.com/hobwekiva/d63508ddb6a728015ace53cb70a1fd5d)
-
-| Type | Functor | Apply | Applicative | Monad | MonoidK | ApplicativeError | MonadError | CoflatMap | Comonad | Bimonad |
-| --------------- |:-------:|:-----------------:|:-----------:|:-----:|:-------:|:-----------------:|:----------:|:---------:|:-------:|:-------:|
-| `Id[A]` | ✔ | ✔ | ✔ | ✔ | ✗ | ✗ | ✗ | ✔ | ✔ |✔ |
-| `Eval[A]` | ✔ | ✔ | ✔ | ✔ | ✗ | ✗ | ✗ | ✔ | ✔ |✔ |
-| `Option[A]` | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✗ |✗ |
-| `Const[K, A]` | ✔ | ✔ (`K:Monoid`) | ✔ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ |✗ |
-| `Either[E, A]` | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✗ | ✗ |✗ |
-| `List[A]` | ✔ | ✔ | ✔ | ✔ | ✔ | ✗ | ✗ | ✔ | ✗ |✗ |
-| `NonEmptyList[A]` | ✔ | ✔ | ✔ | ✔ | ✗ | ✗ | ✗ | ✔ | ✔ |✔ |
-| `Stream[A]` | ✔ | ✔ | ✔ | ✔ | ✔ | ✗ | ✗ | ✔ | ✗ |✗ |
-| `Map[K, A]` | ✔ | ✔ | ✗ | ✗ | ✔ | ✗ | ✗ | ✗ | ✗ |✗ |
-| `Validated[E, A]` | ✔ | ✔ (`E: Semigroup`)| ✔ | ✗ | ✗ | ✔ (`E: Semigroup`)| ✗ | ✗ | ✗ |✗ |
-| `Reader[E, A]` | ✔ | ✔ | ✔ | ✔ | ✗ | ✗ | ✗ | ✗ | ✗ |✗ |
-| `Writer[E, A]` | ✔ | ✔ (`E:Monoid`) | ✔ | ✔ | ✗ | ✗ | ✗ | ✔ | ✗ |✗ |
-
-
-
+| Type | Functor | Apply | Applicative | Monad | MonoidK | ApplicativeError | MonadError | CoflatMap | Comonad | Bimonad |
+| ----------------- |:-------:|:-----------------:|:-----------:|:-----:|:-------:|:-----------------:|:----------:|:---------:|:-------:|:-------:|
+| `Id[A]` | ✔ | ✔ | ✔ | ✔ | ✗ | ✗ | ✗ | ✔ | ✔ |✔ |
+| `Eval[A]` | ✔ | ✔ | ✔ | ✔ | ✗ | ✗ | ✗ | ✔ | ✔ |✔ |
+| `Option[A]` | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✗ |✗ |
+| `Const[K, A]` | ✔ | ✔ (`K:Monoid`) | ✔ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ |✗ |
+| `Either[E, A]` | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✗ | ✗ |✗ |
+| `List[A]` | ✔ | ✔ | ✔ | ✔ | ✔ | ✗ | ✗ | ✔ | ✗ |✗ |
+| `NonEmptyList[A]` | ✔ | ✔ | ✔ | ✔ | ✗ | ✗ | ✗ | ✔ | ✔ |✔ |
+| `Stream[A]` | ✔ | ✔ | ✔ | ✔ | ✔ | ✗ | ✗ | ✔ | ✗ |✗ |
+| `Map[K, A]` | ✔ | ✔ | ✗ | ✗ | ✔ | ✗ | ✗ | ✗ | ✗ |✗ |
+| `Validated[E, A]` | ✔ | ✔ (`E: Semigroup`)| ✔ | ✗ | ✗ | ✔ (`E: Semigroup`)| ✗ | ✗ | ✗ |✗ |
+| `Reader[E, A]` | ✔ | ✔ | ✔ | ✔ | ✗ | ✗ | ✗ | ✗ | ✗ |✗ |
+| `Writer[E, A]` | ✔ | ✔ (`E:Monoid`) | ✔ | ✔ | ✗ | ✗ | ✗ | ✔ | ✗ |✗ |
## Further reading
-* [Returning the "Current" Type in Scala][fbounds]
-
+* [Returning the "Current" Type in Scala][fbounds]
[fbounds]: http://tpolecat.github.io/2015/04/29/f-bounds.html "Returning the "Current" Type in Scala"