You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: source_md/making-our-own-types-and-typeclasses.md
+16-16Lines changed: 16 additions & 16 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1836,23 +1836,23 @@ Man, that looks weird.
1836
1836
How would we make a type that could be an instance of that strange typeclass?
1837
1837
Well, let's look at what its kind would have to be.
1838
1838
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 -> *) -> *`.
1843
1843
Wow.
1844
1844
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 -> *) -> *`.
1846
1846
Here's one way of going about it.
1847
1847
1848
1848
```{.haskell:hs}
1849
1849
data Frank a b = Frank {frankField :: b a} deriving (Show)
1850
1850
```
1851
1851
1852
-
How do we know this type has a kind of `* -> (* -> *) - > *`?
1852
+
How do we know this type has a kind of `k -> (k -> *) - > *`?
1853
1853
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`.
1856
1856
Let's make some `Frank` values and check out their types.
1857
1857
1858
1858
```{.haskell:hs}
@@ -1892,32 +1892,32 @@ Let's do some more type-foo.
1892
1892
We have this data type:
1893
1893
1894
1894
```{.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 }
1896
1896
```
1897
1897
1898
1898
And now we want to make it an instance of `Functor`.
1899
1899
`Functor` wants types of kind `* -> *` but `Barry` doesn't look like it has that kind.
1900
1900
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 -> *`.
1902
1902
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 -> * -> *`.
1905
1905
Let's check that with GHCi.
1906
1906
1907
1907
```{.haskell:hs}
1908
1908
ghci> :k Barry
1909
-
Barry :: (* -> *) -> * -> * -> *
1909
+
Barry :: (k -> *) -> k -> * -> *
1910
1910
```
1911
1911
1912
1912
Ah, we were right.
1913
1913
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`.
1916
1916
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`.
1917
1917
The third type parameter from `Barry` will have to change and we see that it's conveniently in its own field.
1918
1918
1919
1919
```{.haskell:hs}
1920
-
instance Functor (Barry a b) where
1920
+
instance Functor (Barry c d) where
1921
1921
fmap f (Barry {yabba = x, dabba = y}) = Barry {yabba = f x, dabba = y}
0 commit comments