官术网_书友最值得收藏!

Type errors and inference

The other main kind of compiler error you will see is a type error. A type error is an error that arises when a type (or a value of a type) is used in a way that's not allowed by the type definition.

These are more interesting errors because you're likely to come across them for the rest of your programming career, during which you should expect to continue seeing large productivity and code quality benefits from type errors forcing better design thinking and bug reduction.

Type errors are also heavily tied into Reason's type inference engine, which through a process of elimination works out exactly what the types should be for every piece of the code. Let's look at a few simple type errors and the code that will trigger them. We will also explain the type inference rules that led to the error.

First, let's try the division problem we posted earlier (the bold parts are colored red in Reason's error message):

(Output from bsb -w)
We've found a bug for you!
/Users/yawar/src/learning-tydd-reason/src/Ch02/Ch02_Demo.re 8:14-18

6 │ /* ... elided ... */
7 │
8 │ let result = "Bob" / 5;

This has type:
string
But somewhere wanted:
int

Let's look at the process of elimination by which Reason arrives at type errors:

  • Assigns types to the smallest possible parts of the expression, one by one
  • Tries to fit all the types together like puzzle pieces
    • If they fit, pass typechecker
    • If they don't fit, raise a type error

The following diagram shows the type inference and checking process (read from left to right):

The type error arises from the fact that "Bob" is a string (anything inside double-quotes is inferred to be a string), whereas the division operator (/) by definition requires two int variables as input. However, Reason can still infer result to be an int because it knows the division operator outputs an int.

Now, let's try a slightly more interesting type error, from not creating a record correctly, shown as follows:

(Output from bsb -w)
We've found a bug for you!
/Users/yawar/src/learning-tydd-reason/src/Ch02/Ch02_Demo.re 6:51-53

4 │
5 │ let bob = {id: 1, name: "Bob"};
6 │ let acmeCo = {id: 1, name: "Acme Co.", employees: bob};

This has type:
person
But somewhere wanted:
list(person)

The following diagram shows the typechecking process for a record:

Here, the type error arises because one of the components of the record does not have the correct type. You can compare the code in the error message with the source code to exact

You may be curious to know why the division type error was reported the way it was, when it may have been more natural to work from left to right and produce an error like string does not support division by ints. This is because the typechecker works on the abstract syntax tree of the program – that is, an internal representation of the program itself after it has been parsed (and verified as free of syntax errors). The AST is structured, as you might have guessed, as a tree, and in the tree, operations and function calls are the parent nodes of their arguments. So, the operations are assigned types first and then their arguments. Hence you see "Bob" as the thing that caused the type mismatch, instead of (/).

Theoretically, though, typechecking could go in either direction – from the root of the AST to its leaf nodes or the other way round as normal. You may often hear the process of fitting the types together referred to as unification, which means the same thing. If instead of "Bob" , the first operand had been, for example, 10 (of type int), Reason would have been able to unify their types (int and int) and thus pass typechecking.

主站蜘蛛池模板: 丰宁| 横山县| 勐海县| 吉安市| 抚州市| 澎湖县| 陈巴尔虎旗| 云安县| 乌拉特后旗| 六安市| 盘锦市| 子长县| 织金县| 中牟县| 曲阜市| 修武县| 抚远县| 五华县| 乌恰县| 读书| 林芝县| 读书| 阿图什市| 茶陵县| 扬州市| 临泉县| 建阳市| 威信县| 宣汉县| 昌都县| 廊坊市| 榆中县| 荣成市| 河源市| 荃湾区| 噶尔县| 江源县| 保德县| 莎车县| 西华县| 海淀区|