Посмотрите этот ответ StackOverflow относительно вывода типа Go. Я сам не знаком с Go, но на основании этого ответа он выглядит как односторонний «вывод типа» (если позаимствовать некоторую терминологию C ++). Это означает, что если у вас есть:
x := y + z
затем тип x
определяется путем выяснения типа y + z
, что довольно легко сделать для компилятора. Для этого типы y
и z
должны быть известны априори : это можно сделать с помощью аннотаций типов или вывести из литералов, назначенных им.
Напротив, большинство функциональных языков имеют вывод типа, который использует всю возможную информацию в модуле (или функцию, если алгоритм вывода является локальным) для получения типа переменных. Сложные алгоритмы вывода (такие как Хиндли-Милнер) часто вовлекают некоторую форму объединения типов (немного похоже на решение уравнений) за кулисами. Например, в Haskell, если вы напишите:
let x = y + z
тогда Haskell может определить тип не только, x
но y
и z
просто, основываясь на том факте, что вы выполняете сложение для них. В этом случае:
x :: Num a => a
y :: Num a => a
z :: Num a => a
(Нижний регистр a
здесь обозначает полиморфный тип , часто называемый «обобщением» в других языках, таких как C ++. Эта Num a =>
часть является ограничением, указывающим, что a
поддержка типа имеет некоторое представление о добавлении.)
Вот более интересный пример: комбинатор с фиксированной точкой, который позволяет определить любую рекурсивную функцию:
let fix f = f (fix f)
Обратите внимание, что нигде мы не указали тип f
и не указали тип fix
, но компилятор Haskell может автоматически выяснить, что:
f :: t -> t
fix :: (t -> t) -> t
Это говорит о том, что:
- Параметр
f
должен быть функцией от произвольного типа t
до того же типа t
.
fix
это функция, которая получает параметр типа t -> t
и возвращает результат типа t
.
x
,y
,z
такая жеNum
тип Эрика, но они все еще могут бытьInteger
s,Double
S,Ratio Integer
S ... Haskell готов сделать произвольный выбор между числовыми типами, но не для других классов типов.Вывод типа в Go чрезвычайно ограничен и чрезвычайно прост. Он работает только в одной языковой конструкции (объявление переменной) и просто берет тип с правой стороны и использует его в качестве типа для переменной с левой стороны.
Вывод типов в Haskell можно использовать везде, его можно использовать для определения типов для всей программы. Он основан на унификации, что означает, что (концептуально) все типы выводятся «сразу», и все они могут влиять друг на друга: в Go информация о типах может перетекать только из правой части объявления переменной в левую. стороны, никогда не в другом направлении и никогда вне объявления переменной; в Haskell информация о типах свободно распространяется во всех направлениях по всей программе.
Тем не менее, система типов Haskell настолько мощна, что вывод типа может фактически не выводить тип (или, точнее, должны быть введены ограничения, чтобы тип всегда мог быть выведен). Система типов Go настолько проста (без подтипов, без параметрического полиморфизма), и ее вывод настолько ограничен, что всегда успешен.
источник