Ответ 1
Короче говоря, тип x
обобщается на let
. Это ключевой шаг в алгоритме вывода типа Hindley-Milner.
Конкретно, let x = Nothing
изначально присваивает x
тип Maybe t
, где t
- переменная нового типа. Затем тип обобщается, универсально оценивая все его переменные типа (технически: кроме тех, которые используются в другом месте, но здесь мы имеем только t
). Это вызывает x :: forall t. Maybe t
x :: forall t. Maybe t
. Обратите внимание, что это точно такой же тип, как Nothing :: forall t. Maybe t
Nothing :: forall t. Maybe t
.
Следовательно, каждый раз, когда мы используем x
в нашем коде, это относится к потенциально другому типу Maybe t
, как Nothing
. По этой причине (x, x)
получает тот же тип, что и (Nothing, Nothing)
.
Вместо этого лямбды не имеют одного и того же шага обобщения. Для сравнения (\x → (x, x)) Nothing
"только" не имеет типа forall t. (Maybe t, Maybe t)
forall t. (Maybe t, Maybe t)
, где оба компонента вынуждены быть одного типа. Здесь x
снова присваивается тип Maybe t
, с t
fresh, но он не является обобщенным. Тогда (x, x)
присваивается тип (Maybe t, Maybe t)
. Только на верхнем уровне мы обобщаем добавление forall t
, но в этот момент слишком поздно, чтобы получить гетерогенную пару.