Skip to content

Commit af1214f

Browse files
committed
update section on kinds
1 parent f75324b commit af1214f

1 file changed

Lines changed: 16 additions & 16 deletions

File tree

source_md/making-our-own-types-and-typeclasses.md

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1836,23 +1836,23 @@ Man, that looks weird.
18361836
How would we make a type that could be an instance of that strange typeclass?
18371837
Well, let's look at what its kind would have to be.
18381838
Because `j a` is used as the type of a value that the `tofu` function takes as its parameter, `j a` has to have a kind of `*`.
1839-
We assume `*` for `a` and so we can infer that `j` has to have a kind of `* -> *`.
1840-
We see that `t` has to produce a concrete value too and that it takes two types.
1841-
And knowing that `a` has a kind of `*` and `j` has a kind of `* -> *`, we infer that `t` has to have a kind of `* -> (* -> *) -> *`.
1842-
So it takes a concrete type (`a`), a type constructor that takes one concrete type (`j`) and produces a concrete type.
1839+
It looks like the kind of `a` is probably `*`, but it's not certain, so let's just call it `k` for now.
1840+
We can infer that `j` has to have a kind of `k -> *`.
1841+
We see that `t` has to produce a concrete value too and that it takes two arguments.
1842+
And knowing that `a` has a kind of `k` and `j` has a kind of `k -> *`, we infer that `t` has to have a kind of `k -> (k -> *) -> *`.
18431843
Wow.
18441844

1845-
OK, so let's make a type with a kind of `* -> (* -> *) -> *`.
1845+
OK, so let's make a type with a kind of `k -> (k -> *) -> *`.
18461846
Here's one way of going about it.
18471847

18481848
```{.haskell:hs}
18491849
data Frank a b = Frank {frankField :: b a} deriving (Show)
18501850
```
18511851

1852-
How do we know this type has a kind of `* -> (* -> *) - > *`?
1852+
How do we know this type has a kind of `k -> (k -> *) - > *`?
18531853
Well, fields in ADTs are made to hold values, so they must be of kind `*`, obviously.
1854-
We assume `*` for `a`, which means that `b` takes one type parameter and so its kind is `* -> *`.
1855-
Now we know the kinds of both `a` and `b` and because they're parameters for `Frank`, we see that `Frank` has a kind of `* -> (* -> *) -> *` The first `*` represents `a` and the `(* -> *)` represents `b`.
1854+
We assume `k` for `a`, and `b` takes it as its argument so its kind is `k -> *`.
1855+
Now we know the kinds of both `a` and `b` and because they're parameters for `Frank`, we see that `Frank` has a kind of `k -> (k -> *) -> *` The first `k` represents `a` and the `(k -> *)` represents `b`.
18561856
Let's make some `Frank` values and check out their types.
18571857

18581858
```{.haskell:hs}
@@ -1892,32 +1892,32 @@ Let's do some more type-foo.
18921892
We have this data type:
18931893

18941894
```{.haskell:hs}
1895-
data Barry t k p = Barry { yabba :: p, dabba :: t k }
1895+
data Barry t m p = Barry { yabba :: p, dabba :: t m }
18961896
```
18971897

18981898
And now we want to make it an instance of `Functor`.
18991899
`Functor` wants types of kind `* -> *` but `Barry` doesn't look like it has that kind.
19001900
What is the kind of `Barry`?
1901-
Well, we see it takes three type parameters, so it's going to be `something -> something -> something -> *`.
1901+
Well, we see it takes three arguments, so it's going to be `something -> something -> something -> *`.
19021902
It's safe to say that `p` is a concrete type and thus has a kind of `*`.
1903-
For `k`, we assume `*` and so by extension, `t` has a kind of `* -> *`.
1904-
Now let's just replace those kinds with the *somethings* that we used as placeholders and we see it has a kind of `(* -> *) -> * -> * -> *`.
1903+
For `m`, we assume `k` and so by extension, `t` has a kind of `k -> *`.
1904+
Now let's just replace those kinds with the *somethings* that we used as placeholders and we see it has a kind of `(k -> *) -> k -> * -> *`.
19051905
Let's check that with GHCi.
19061906

19071907
```{.haskell:hs}
19081908
ghci> :k Barry
1909-
Barry :: (* -> *) -> * -> * -> *
1909+
Barry :: (k -> *) -> k -> * -> *
19101910
```
19111911

19121912
Ah, we were right.
19131913
How satisfying.
1914-
Now, to make this type a part of `Functor` we have to partially apply the first two type parameters so that we're left with `* -> *`.
1915-
That means that the start of the instance declaration will be: `instance Functor (Barry a b) where`.
1914+
Now, to make this type a part of `Functor` we have to fill the first two parameters so that we're left with `* -> *`.
1915+
That means that the start of the instance declaration will be: `instance Functor (Barry … …) where`.
19161916
If we look at `fmap` as if it was made specifically for `Barry`, it would have a type of `fmap :: (a -> b) -> Barry c d a -> Barry c d b`, because we just replace the `Functor`'s `f` with `Barry c d`.
19171917
The third type parameter from `Barry` will have to change and we see that it's conveniently in its own field.
19181918

19191919
```{.haskell:hs}
1920-
instance Functor (Barry a b) where
1920+
instance Functor (Barry c d) where
19211921
fmap f (Barry {yabba = x, dabba = y}) = Barry {yabba = f x, dabba = y}
19221922
```
19231923

0 commit comments

Comments
 (0)