on d4e9599 help sign in
elk/docs/hints/type-annotations.md
60 lines 2.7 kB history raw
1# Hints for Type Annotation Problems
3At the root of this kind of issue is always the fact that a type annotation in your code does not match the corresponding definition. Now that may mean that the type annotation is "wrong" or it may mean that the definition is "wrong". The compiler cannot figure out your intent, only that there is some mismatch.
5This document is going to outline the various things that can go wrong and show some examples.
8## Annotation vs. Definition
10The most common issue is with user-defined type variables that are too general. So lets say you have defined a function like this:
12```elm
13addPair : (a, a) -> a
14addPair (x, y) =
15 x + y
16```
18The issue is that the type annotation is saying "I will accept a tuple containing literally *anything*" but the definition is using `(+)` which requires things to be numbers. So the compiler is going to infer that the true type of the definition is this:
20```elm
21addPair : (number, number) -> number
22```
24So you will probably see an error saying "I cannot match `a` with `number`" which is essentially saying, you are trying to provide a type annotation that is **too general**. You are saying `addPair` accepts anything, but in fact, it can only handle numbers.
26In cases like this, you want to go with whatever the compiler inferred. It is good at figuring this kind of stuff out ;)
29## Annotation vs. Itself
31It is also possible to have a type annotation that clashes with itself. This is probably more rare, but someone will run into it eventually. Let's use another version of `addPair` with problems:
33```elm
34addPair : (Int, Int) -> number
35addPair (x, y) =
36 x + y
37```
39In this case the annotation says we should get a `number` out, but because we were specific about the inputs being `Int`, the output should also be an `Int`.
42## Annotation vs. Internal Annotation
44A quite tricky case is when an outer type annotation clashes with an inner type annotation. Here is an example of this:
46```elm
47filter : (a -> Bool) -> List a -> List a
48filter isOkay list =
49 let
50 keepIfOkay : a -> Maybe a
51 keepIfOkay x =
52 if isOkay x then Just x else Nothing
53 in
54 List.filterMap keepIfOkay list
55```
57This case is very unfortunate because all the type annotations are correct, but there is a detail of how type inference works right now that **user-defined type variables are not shared between annotations**. This can lead to probably the worst type error messages we have because the problem here is that `a` in the outer annotation does not equal `a` in the inner annotation.
59For now the best route is to leave off the inner annotation. It is unfortunate, and hopefully we will be able to do a nicer thing in future releases.