# Lecture 4 — 2018-01-25

## Kinds and type classes

This lecture is written in literate Haskell; you can download the raw source.

`module Lec04 where`

Just as types classify terms, kinds classify types. Haskell has two kinds:

`k ::= * | * -> *`

First, `*`

, pronounced “star”, is the kind of complete types, which classify terms. `Int`

has kind `*`

, as does `Bool`

. The types `[Int]`

and `Maybe Bool`

have kind `*`

, too. The types `[]`

(read “list”) or `Maybe`

have kind `* -> *`

: they’re *type constructors*. There are no terms with the type `[]`

or `Maybe`

… terms only ever have types of kind `*`

.

But: if you give `[]`

a type, then you will have a complete type, as in `[Int]`

.

Next, the *type* of functions `(->)`

has the kind `* -> * -> *`

. If you give `(->)`

two type parameters `a`

and `b`

, you will have a function type, `a -> b`

. If you give it just one parameter, you will have a type constructor `(a ->)`

of kind `* -> *`

. It is unfortunately somewhat confusing that `->`

means two different things here: it’s both the function type *and* the ‘arrow’ kind. Rough stuff.

Just as `:t`

in GHCi will tell you the type of a term, `:k`

will tell you the type of a kind. For example:

```
GHCi, version 7.10.2: http://www.haskell.org/ghc/ :? for help
Prelude> :k []
[] :: * -> *
Prelude>
```

Why do we care about kinds? In the next few classes, we’ll be looking at non-`*`

kinded types in order to talk about groups of behavior. The next bit will be a first foray into types with interesting kinds.

**Interface-like typeclasses**

We didn’t get a chance to look at type classes that characterize behavior. The `Listlike`

type class characterizes *type constructors* of kind `* -> *`

that behave like lists.

```
class Listlike f where
nil :: f a
cons :: a -> f a -> f a
```

Note that `f`

must have kind `* -> *`

, because we apply it to the type parameter `a`

, which must have kind `*`

. Why? Because `cons`

has type `a -> f a -> f a`

, and `(->)`

has kind `* -> * -> *`

and is applied to `a`

.

```
openCons :: f a -> Maybe (a,f a)
hd :: f a -> Maybe a
hd l =
case openCons l of
Nothing -> Nothing
Just (x,_) -> Just x
tl :: f a -> Maybe (f a)
tl l =
case openCons l of
Nothing -> Nothing
Just (_,xs) -> Just xs
isNil :: f a -> Bool -- true iff openCons returns Nothing
isNil l =
case openCons l of
Nothing -> True
Just _ -> False
foldRight :: (a -> b -> b) -> b -> f a -> b
foldRight f b l =
case openCons l of
Nothing -> b -- list is empty
Just (h,t) -> f h (foldRight f b t)
foldLeft :: (b -> a -> b) -> b -> f a -> b
foldLeft f b l =
case openCons l of
Nothing -> b
Just (h,t) -> foldLeft f (f b h) t
each :: (a -> b) -> f a -> f b
each f = foldRight (cons . f) nil
append :: f a -> f a -> f a
append xs ys = foldRight cons ys xs
```

We can show that the list *type constructor*, `[]`

, which has kind `* -> *`

, is an instance of the `Listlike`

class. On an intuitive level, this should be no surprise: lists are indeed listlike.

```
instance Listlike [] where
nil = []
cons = (:)
openCons [] = Nothing
openCons (x:xs) = Just (x,xs)
foldRight = foldr
foldLeft = foldl
-- just take each and append as the usual
```

We’ve defined here a *minimal* instance: for every undefined type signature in the class, we give a definition. If anything were defined circularly—say, `openCons`

in terms of `isNil`

, `hd`

, and `tl`

—we’d have to define at least enough to “break the loop”. Finally, it’s critical that we listen to the comments in the class—if we defined an `isNil`

that disagreed with `openCons`

, all kinds of crazy things would happen!

Once we defined our minimal instance, we wrote a function that *only* uses the `Listlike`

type class, without any knowledge of the underlying implementation `f`

.

```
myConcat :: Listlike f => f (f a) -> f a
myConcat = foldRight append nil
```

For example, the following wouldn’t type check:

```
myConcat' :: Listlike f => f (f a) -> f a
myConcat' = foldRight (++) []
```

Why not? Haskell sees that `f`

is some `Listlike`

type, but that could (in principle) be anything. And just because `([])`

happens to be `Listlike`

, who’s to say that our `f`

is `([])`

this time?

Here’s an alternative implementation: union trees.

```
data UnionTree a =
Empty -- []
| Singleton a -- [a]
| Union { left :: UnionTree a, right :: UnionTree a }
deriving Show
```

```
instance Listlike UnionTree where
-- nil :: f a
nil = Empty
-- cons :: a -> f a -> f a
cons x xs = Union (Singleton x) xs
-- openCons :: f a -> Maybe (a,f a)
openCons Empty = Nothing
openCons (Singleton x) = Just (x,Empty)
openCons (Union l r) =
case openCons l of
Nothing -> openCons r
Just (x,l') -> Just (x,Union l' r)
append = Union -- O(1) vs. O(n) !!!!
foldRight f b u =
case openCons u of
Nothing -> b
Just (h,t) -> f h (foldRight f b t)
foldLeft f b u =
case openCons u of
Nothing -> b
Just (h,t) -> foldLeft f (f b h) t
```

By defining `append`

inside the `Listlike`

class, we were able to override the definition for the `UnionTree`

instance with one that’s much more efficient. Neato! For an example of this in action, checkout the `Foldable`

type class.

```
ut1,ut2,ut3 :: UnionTree String
ut1 = Union (Singleton "hi") (Singleton "there")
ut2 = Union Empty Empty
ut3 = Union (Singleton "everybody") Empty
ut = myConcat (Union (Singleton ut1) (Union (Singleton ut2) (Singleton ut3)))
toList :: Listlike f => f a -> [a]
toList l = foldRight (:) [] l
fromList :: Listlike f => [a] -> f a
fromList l = foldr cons nil l
```