Explorar el Código

typeclassopedia: a glimpse of functors.

Lucas Stadler %!s(int64=11) %!d(string=hace) años
padre
commit
ec1ca4b97e
Se han modificado 1 ficheros con 111 adiciones y 0 borrados
  1. 111 0
      hs/Typeclassopedia.lhs

+ 111 - 0
hs/Typeclassopedia.lhs

@ -0,0 +1,111 @@
1
# Typeclassopedia: A journey
2
3
I don't think Haskell is scary, but there still is a lot to learn after
4
you finish LYAH. I kind of stopped there, because I was still scared and
5
because it felt so good already, why continue?
6
7
Well, because Haskell is so much more and I think it's one of the things
8
that make Haskell special: Working with high-level abstractions that
9
make things possible that were previously unthinkable.
10
11
I think I've missed a lot so far, because if you "just use" Haskell you
12
aren't really in control, one might even say that you aren't really
13
writing Haskell, you've stopped right after the doorstep.
14
15
So, let's find out what's behind the doorstep.
16
17
## Functors
18
19
> class Functor f where
20
>   fmap :: (a -> b) -> f a -> f b
21
22
Instances for `Either e` and `((->) e)`.
23
24
Mhh, `Either e` seems easier, although it also looks a bit weird:
25
`Either` is usually about two things, the `l` and the `r` part.
26
27
Ok, so why are we declaring `Either e` the `Functor` instance, why not
28
just `Either`? (Excuse my ignorance here, I've really been avoiding this
29
stuff, so I'll have to be very explicit about everything for a while.)
30
31
Well, let's have a look at the `fmap` again, then. It's type is `(a ->
32
b) -> f a -> f b`, so for `Either e` it is `(a -> b) -> Either e a ->
33
Either e b`. That's a hint why it is this way: the `l` (here `e`) part
34
is usually used for errors and `fmap`ing over that is probably not very
35
interesting most of the time. So we "change" the `r` part.
36
37
But still, *can* we define a `Functor` instance for `Either`? The type
38
would be `(a -> b) -> Either a -> Either b`. I think that would not
39
work, because we haven't "applied" `Either` fully, so likely Haskell
40
will not like it.
41
42
But what does `Either l` mean? It's incomplete, but we if we "apply"
43
some other type to it then we have a type we can use. Is this what kinds
44
are? Some kind of marker for such incomplete types? Is there a name for
45
those things?
46
47
Playing with this shows that those things really aren't allowed:
48
49
```
50
λ :kind Either
51
* -> * -> Either
52
λ :kind Either Int
53
* -> *
54
λ Either Int -> Either Int
55
<interactive>:1:1:
56
    Expecting one more argument to `Either Int'
57
    In a type in a GHCi command: Either Int -> Either Int
58
```
59
60
First, `Either` is a *type constructor*, e.g. you can't use it right
61
away, but you build types with it. You can, however, also apply it
62
partially and only later decide on the other parameters.
63
64
For example, we can have `WithError`, which is just `Either String`.
65
But to use it we still have to "apply" it to some other type.
66
67
> type WithError = Either String -- "incomplete"
68
>
69
> zeroIsSpecial :: Int -> WithError Int
70
> zeroIsSpecial 0 = Left "you can't have my precious zero, sorry"
71
> zeroIsSpecial n = Right n
72
73
The [page on Kinds][kinds] on the Haskell wiki tells me that those
74
complete types, e.g. types with kind `*` are called monomorphic (data)
75
types. Are there polymorphic data types? Well, there surely are, but we
76
can't compute with them. (Surely? Yes, `Either`, for example. But what
77
about ordinary constructors with two arguments? Mhh.. ok, haskell says
78
they aren't type constructors, so they have no kind.)
79
80
[kinds]: http://www.haskell.org/haskellwiki/Kind
81
82
Ok, let's come back to this later.
83
84
So, let's define a `Functor` instance for `Either e`. But first, what
85
will it "mean"? If we make something a Functor, then we look at it as a
86
whole, so `Either e` as an instance of `Functor` is not two parts, but
87
one. It's a container for things. And to the value in that container we
88
want to apply a function. Let's do that first.
89
90
> instance Functor (Either e) where
91
>   fmap f (Right r) = Right $ f r
92
>   fmap f l = l
93
94
That was... easy. Am I missing something?
95
96
What about `((->) e)` then? That seems trickier. First, `(->)`s kind is
97
`* -> * -> *`, just as `Either`s was, but I find it a little bit more
98
difficult to see what that means.
99
100
For `Either` it was that we had to supply the types for the `Left` and
101
`Right` parts. And for `(->)` it means which arguments we want the
102
function type to have. So, `((->) e)` means something with an `e` as an
103
argument.
104
105
The Typeclassopedia mentions that the `e` is read-only and that this
106
type is also known as `Reader`, so let's look at what it does.
107
108
> instance Functor ((->) e) where
109
>   fmap :: (a -> b) -> (((->) e) a) -> (((->) e) b)
110
>   -- aka  (a -> b) -> (e -> a) -> (e -> b)
111
>   fmap f g =