Чтобы понять эту подпись типа, вам нужно сначала понять каррирование.
Определение, подобное
fun sum a b = a + b
имеет тип int -> int -> int
.
Это функция одной переменной (целого числа), где возвращаемое значение само является функцией, которая отправляет целые числа в целые числа.
Например, val f = sum 1
присваивает f
функцию, которая добавляет единицу к своему входу (другими словами, функцию-преемник), так что, например, f 5
оценивается как 6.
На практике такие функции часто используются как sum 3 4
, но то, что происходит там, не является передачей 2 значений в sum
. Вместо этого передается одно значение 3, которое возвращает функцию, и это возвращаемое значение затем применяется к 4. Таким образом, sum 3 4
следует интерпретировать как (sum 3) 4
, а не sum (3,4)
, что было бы ошибкой типа.
Обратите внимание, что это принципиально отличается от чего-то вроде
fun add (a,b) = a + b
которая является функцией двух переменных, имеет тип int * int -> int
, который отличается от типа суммы int -> int -> int
. Последнее не является синтаксическим сахаром для первого, но имеет принципиально иную семантику.
Читая что-то вроде int -> int -> int
, вы должны читать его как правоассоциативное. Другими словами, это то же самое, что и int -> (int -> int)
.
Еще одна вещь, которая происходит с ('a * 'b -> 'b) -> 'b -> 'a list -> 'b
, — это использование переменных типов 'a, 'b
. Это означает, что тип, который вы пытаетесь проанализировать, относится к полиморфной функции более высокого порядка. Это 'a
и 'b
может представлять любой тип.
Собрав все вместе, функция f
типа ('a * 'b -> 'b) -> 'b -> 'a list -> 'b
— это функция, которая принимает в качестве входных данных любую функцию, тип которой имеет вид 'a * 'b -> 'b
(функция двух переменных, возвращаемый тип которой является типом второй переменной). Возвращаемое значение f
является функцией вида 'b -> 'a list -> 'b
. Последняя представляет собой функцию, которая принимает элемент типа 'b
и возвращает функцию, которая отправляет 'a lists
объектам типа 'b
.
Подводя итог, можно сказать, что f
— это каррированная функция, которая принимает функцию типа ('a * 'b -> 'b)
, значение типа 'b
, список значений типа 'a
и возвращает значение типа 'b
. Это достаточно точно, но не думайте, что это эквивалентно функции типа
('a * 'b -> 'b) * 'b * 'a list -> 'b
Между прочим, две самые полезные функции в SML, foldl
и foldr
, имеют тип ('a * 'b -> 'b) -> 'b -> 'a list -> 'b
, так что это не просто академическое упражнение. Способность распаковывать такие описания типов является ключом к правильному использованию таких функций.
person
John Coleman
schedule
06.12.2016