Есть пара понятий, которые вам необходимо понять, чтобы понять смысл этой сигнатуры типа, и я не знаю, какие из них вы уже используете, поэтому я изо всех сил пытался объяснить каждую важную концепцию:
Curry
Как вы знаете, если у вас есть тип foo -> bar
, это описывает функцию, принимающую аргумент типа foo
и возвращающую результат типа bar
.Поскольку ->
ассоциативно справа, тип foo -> bar -> baz
совпадает с foo -> (bar -> baz)
и поэтому описывает функцию, принимающую аргумент типа foo
и возвращающую значение типа bar -> baz
, что означает, что возвращаемое значение являетсяфункция, принимающая значение типа bar
и возвращающая значение типа baz
.
Такая функция может быть вызвана как my_function my_foo my_bar
, которая, поскольку приложение функции является левоассоциативной, совпадает с (my_function my_foo) my_bar
, то есть он применяет my_function
к аргументу my_foo
, а затем применяет функцию, возвращаемую в результате к аргументу my_bar
.
Поскольку его можно вызывать вот так, функциятип foo -> bar -> baz
часто называют «функцией, принимающей два аргумента», и я сделаю это в оставшейся части этого ответа.
Переменные типа
Если вы определите функцию, такую как let f x = x
,он будет иметь тип 'a -> 'a
.Но 'a
на самом деле не является типом, определенным где-либо в стандартной библиотеке OCaml, так что же это такое?
Любой тип, начинающийся с '
, является так называемой переменной типа .Переменная типа может обозначать любой возможный тип.Таким образом, в приведенном выше примере f
может быть вызван с int
или string
, или list
, или чем-нибудь вообще - это не имеет значения.
Кроме того, если появляется та же переменная типав сигнатуре типа более одного раза это будет означать тот же тип.Таким образом, в приведенном выше примере это означает, что тип возвращаемого значения f
совпадает с типом аргумента.Поэтому, если f
вызывается с int
, возвращается int
.Если он вызывается с string
, он возвращает string
и т. Д.
Таким образом, функция типа 'a -> 'b -> 'a
может принимать два аргумента любых типов (которые могут не совпадать с типом дляпервый и второй аргумент) и возвращает значение того же типа, что и первый аргумент, в то время как функция типа 'a -> 'a -> 'a
будет принимать два аргумента одного типа.
Одно замечание о выводе типа:явно указав для функции сигнатуру типа, OCaml всегда выведет наиболее общий тип, возможный для вас.Поэтому, если функция не использует какие-либо операции, которые работают только с данным типом (например, +
), выведенный тип будет содержать переменные типа.
Теперь, чтобы объяснить тип ...
val something : ('a -> 'b -> 'c) -> ('a -> 'd -> 'b) -> 'a -> 'd -> 'c = <fun>
Эта сигнатура типа говорит вам, что something
- это функция, принимающая четыре аргумента.
Тип первого аргумента - 'a -> 'b -> 'c
.Т.е. функция, принимающая два аргумента произвольного и, возможно, разных типов и возвращающая значение произвольного типа.
Тип второго аргумента - 'a -> 'd -> 'b
.Это снова функция с двумя аргументами.Здесь важно отметить, что первый аргумент функции должен иметь тот же тип, что и первый аргумент первой функции, а возвращаемое значение функции должно иметь тот же тип, что и второй аргумент первой функции.
Тип третьего аргумента 'a
, который также является типом первых аргументов обеих функций.
Наконец, тип четвертого аргумента 'd
, который являетсятип второго аргумента второй функции.
Возвращаемое значение будет иметь тип 'c
, т. е. тип возврата первой функции.