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
+24-20Lines changed: 24 additions & 20 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1852,39 +1852,43 @@ Man, that looks weird.
1852
1852
How would we make a type that could be an instance of that strange typeclass?
1853
1853
Well, let's look at what its kind would have to be.
1854
1854
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 `*`.
1855
-
We assume `*` for `a`and so we can infer that `j` has to have a kind of `* -> *`.
1856
-
We see that `t` has to produce a concrete value too and that it takes two types.
1857
-
And knowing that `a` has a kind of `*` and `j` has a kind of `* -> *`, we infer that `t` has to have a kind of `* -> (* -> *) -> *`.
1858
-
So it takes a concrete type (`a`), a type constructor that takes one concrete type (`j`) and produces a concrete type.
1855
+
It looks like the kind of `a`is probably `*`, but it's not certain, so let's just call it `k` for now.
1856
+
We can infer that `j` has to have a kind of `k -> *`.
1857
+
We see that `t` has to produce a concrete value too and that it takes two arguments.
1858
+
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 -> *) -> *`.
1859
1859
Wow.
1860
1860
1861
-
OK, so let's make a type with a kind of `* -> (* -> *) -> *`.
1861
+
Is that actually correct?
1862
+
Try `:k Tofu` to find out.
1863
+
1864
+
OK, so let's make a type with a kind of `k -> (k -> *) -> *`.
1862
1865
Here's one way of going about it.
1863
1866
1864
1867
```{.haskell:hs}
1865
1868
data Frank a b = Frank {frankField :: b a} deriving (Show)
1866
1869
```
1867
1870
1868
-
How do we know this type has a kind of `* -> (* -> *) - > *`?
1871
+
How do we know this type has a kind of `k -> (k -> *) - > *`?
1869
1872
Well, fields in ADTs are made to hold values, so they must be of kind `*`, obviously.
1870
-
We assume `*` for `a`, which means that `b` takes one type parameter and so its kind is `* -> *`.
1871
-
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`.
1873
+
We assume `k` for `a`, and `b` takes it as its argument so its kind is `k -> *`.
1874
+
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`.
1872
1875
Let's make some `Frank` values and check out their types.
1873
1876
1874
1877
```{.haskell:hs}
1875
1878
ghci> :t Frank {frankField = Just "HAHA"}
1876
-
Frank {frankField = Just "HAHA"} :: Frank [Char] Maybe
1879
+
Frank {frankField = Just "HAHA"} :: Frank String Maybe
1877
1880
ghci> :t Frank {frankField = Node 'a' EmptyTree EmptyTree}
1878
-
Frank {frankField = Node 'a' EmptyTree EmptyTree} :: Frank Char Tree
1881
+
Frank {frankField = Node 'a' EmptyTree EmptyTree}
1882
+
:: Frank Char Tree
1879
1883
ghci> :t Frank {frankField = "YES"}
1880
1884
Frank {frankField = "YES"} :: Frank Char []
1881
1885
```
1882
1886
1883
1887
Hmm.
1884
1888
Because `frankField` has a type of form `a b`, its values must have types that are of a similar form as well.
1885
-
So they can be `Just "HAHA"`, which has a type of `Maybe [Char]` or it can have a value of `['Y','E','S']`, which has a type of `[Char]` (if we used our own list type for this, it would have a type of `List Char`).
1889
+
So they can be `Just "HAHA"`, which has a type of `Maybe String` or it can have a value of `['Y','E','S']`, which has a type of `[Char]` (if we used our own list type for this, it would have a type of `List Char`).
1886
1890
And we see that the types of the `Frank` values correspond with the kind for `Frank`.
1887
-
`[Char]` has a kind of `*` and `Maybe` has a kind of `* -> *`.
1891
+
`String` has a kind of `*` and `Maybe` has a kind of `* -> *`.
1888
1892
Because in order to have a value, it has to be a concrete type and thus has to be fully applied, every value of `Frank blah blaah` has a kind of `*`.
1889
1893
1890
1894
Making `Frank` an instance of `Tofu` is pretty simple.
@@ -1908,32 +1912,32 @@ Let's do some more type-foo.
1908
1912
We have this data type:
1909
1913
1910
1914
```{.haskell:hs}
1911
-
data Barry t k p = Barry { yabba :: p, dabba :: t k }
1915
+
data Barry t m p = Barry { yabba :: p, dabba :: t m }
1912
1916
```
1913
1917
1914
1918
And now we want to make it an instance of `Functor`.
1915
1919
`Functor` wants types of kind `* -> *` but `Barry` doesn't look like it has that kind.
1916
1920
What is the kind of `Barry`?
1917
-
Well, we see it takes three type parameters, so it's going to be `something -> something -> something -> *`.
1921
+
Well, we see it takes three arguments, so it's going to be `something -> something -> something -> *`.
1918
1922
It's safe to say that `p` is a concrete type and thus has a kind of `*`.
1919
-
For `k`, we assume `*` and so by extension, `t` has a kind of `* -> *`.
1920
-
Now let's just replace those kinds with the *somethings* that we used as placeholders and we see it has a kind of `(* -> *) -> * -> * -> *`.
1923
+
For `m`, we assume `k` and so by extension, `t` has a kind of `k -> *`.
1924
+
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 -> * -> *`.
1921
1925
Let's check that with GHCi.
1922
1926
1923
1927
```{.haskell:hs}
1924
1928
ghci> :k Barry
1925
-
Barry :: (* -> *) -> * -> * -> *
1929
+
Barry :: (k -> *) -> k -> * -> *
1926
1930
```
1927
1931
1928
1932
Ah, we were right.
1929
1933
How satisfying.
1930
-
Now, to make this type a part of `Functor` we have to fill the first two type parameters so that we're left with `* -> *`.
1931
-
That means that the start of the instance declaration will be: `instance Functor (Barry a b) where`.
1934
+
Now, to make this type a part of `Functor` we have to fill the first two parameters so that we're left with `* -> *`.
1935
+
That means that the start of the instance declaration will be: `instance Functor (Barry … …) where`.
1932
1936
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`.
1933
1937
The third type parameter from `Barry` will have to change and we see that it's conveniently in its own field.
1934
1938
1935
1939
```{.haskell:hs}
1936
-
instance Functor (Barry a b) where
1940
+
instance Functor (Barry c d) where
1937
1941
fmap f (Barry {yabba = x, dabba = y}) = Barry {yabba = f x, dabba = y}
0 commit comments