Write some more for types series' intro.

This commit is contained in:
Danila Fedorin 2022-06-27 21:34:31 -07:00
parent 8e550dc982
commit d2e8f809d0

View File

@ -76,14 +76,67 @@ complexity in terms of program size. This is a huge jump, taking us from "undeci
"efficient". Once again, approximations prevail. What we have is a fast and
practical way of catching our mistakes.
### Types for Documentation and Thought
### Types for Documentation
To me, type systems aren't only about checking if your program is correct;
they're also about documentation. This way of viewing programs comes to
me from experience with Haskell. In Haskell, the compiler is usually able to
check your program without you ever having to write down any types. You
can write your programs, like `length xs + sum xs`, feel assured that what
can write your programs, like `length xs + sum xs`, and feel assured that what
you wrote isn't complete nonsense. And yet, most Haskell programmers
(myself included) _do_ write the types for all of their functions, by hand.
How come?
The answer is that types can tell you what your code does.
The answer is that types can tell you what your code does. Even nontrivial functions
can often have types that fit on a single line (and that are quite easy to read).
For example, given a function `typecheck`, you could try figure out what it returns by reading
the code, or by meditating on its name. Or, you could read its type:
```Haskell
typecheck :: Expr -> Either Error Type
```
This can be read "given an expression, `typecheck` returns either an error or a type".
Now you know what to expect when calling the function, what arguments it needs,
and you have some idea of what it does. You get all this without ever looking
at the code. As another example, the function `partition` has the following type:
```Haskell
partition :: (a -> Bool) -> [a] -> ([a], [a])
```
This one reads, "given a function that returns true or false, and a list, `partition` returns two lists".
It's not too hard to infer that `partition` divides the given list into two, one list
for items that made the input function true, and one for those that made it false. I say this
without having read a word of `partition`'s documentation, and having never seen its code.
The type is enough to convey that information.
There's more. Types, when viewed in this way, don't just help you understand code you already
have. They can also be used to _find_ code that does what you want. This is the idea behind
[Hoogle](https://hoogle.haskell.org/). Here's an example.
Suppose I have a list of people's middle names. A middle name is just a string (`String` in Haskell).
Not everyone has a middle name, though. To represent a value that may or may not be present,
we can use the `Maybe` type constructor. A list of people's middle names, then, would have
the type `[Maybe String]`, a list of (potentially absent) strings. Now, suppose I wanted to take
this list, and filter out all of the absent middle names, resulting in just a list of strings, `[String]`.
Do I have to do this myself, or is there a function for it? I put a type signature into Hoogle:
```Haskell
[Maybe String] -> [String]
```
Hoogle responds with a function that fits the search, in the `Data.Maybe` module:
```Haskell
catMaybes : [Maybe a] -> [a]
```
Looks like I don't have to implement it myself after all! When working with Haskell,
I consult Hoogle a lot of figure out the names of existing functions that match my needs.
I singled out Haskell in this section, but types in a variety of other languages
make for great documentation. When I wrote Rust code, the types were very useful to
understanding how to use a crate; check out the
[documentation page for `Vec`](https://doc.rust-lang.org/std/vec/struct.Vec.html), for instance.
Documentation of Elm packages always lists functions' types (see [documentation for `Parser`](https://package.elm-lang.org/packages/elm/parser/latest/Parser), for example). Even C++ type signatures
listed by Doxygen can be quite useful; I, for one, got a lot out of the [LLVM documentation](https://llvm.org/doxygen/classllvm_1_1IRBuilderBase.html).