Вот моя ментальная модель того, что происходит, которая может соответствовать или не соответствовать реальности.
let rec f x =
Хорошо, на данный момент мы знаем, что f
- это функция, которая принимает аргумент x
. Таким образом, имеем:
f: 'a -> 'b
x: 'a
для некоторых 'a
и 'b
. Далее:
(g x)
Хорошо, теперь мы знаем, g
- это функция, которая может быть применена к x
, поэтому мы добавляем
g: 'a -> 'c
к нашему списку информации. Продолжение ...
(g x) + 5
Ага, тип возврата g
должен быть int
, так что теперь мы решили 'c=int
. На данный момент мы имеем:
f: 'a -> 'b
x: 'a
g: 'a -> int
Двигаемся дальше ...
and g x =
Хорошо, здесь есть другой x
, давайте предположим, что вместо исходного кода было y
, чтобы сделать вещи более очевидными. То есть давайте перепишем код как
and g y = f (y + 5);;
Хорошо, мы находимся на
and g y =
так что теперь наша информация:
f: 'a -> 'b
x: 'a
g: 'a -> int
y: 'a
, поскольку y
является аргументом g
... и мы продолжаем:
f (y + 5);;
и это говорит нам от y+5
, что y
имеет тип int
, который решает 'a=int
. И поскольку это возвращаемое значение g
, которое, как мы уже знаем, должно быть int
, это решает 'b=int
. Это было много за один шаг, если код был
and g y =
let t = y + 5 in
let r = f t in
f r;;
тогда первая строка будет показывать y
как int
, таким образом, решение для 'a
, а затем следующая строка скажет, что r
имеет тип 'b
, а затем последняя строка - возвращаемая g
, который решает 'b=int
.