Hay un par de conceptos que usted necesita entender para dar sentido a este tipo de firma y no sé cuáles ya lo hacen, así que hice mi mejor esfuerzo para explicar cada concepto importante:
Currying
Como usted sabe, si tiene el tipo foo -> bar
, esto describe una función que toma un argumento de tipo foo
y devuelve un resultado del tipo bar
. Dado que ->
es asociativo correcto, el tipo foo -> bar -> baz
es el mismo que foo -> (bar -> baz)
y describe así una función tomando un argumento del tipo foo
y devolviendo un valor de tipo bar -> baz
, lo que significa que el valor devuelto es una función tomando un valor del tipo bar
y devolviendo un valor del tipo baz
.
Tal función puede ser llamada como my_function my_foo my_bar
, que por aplicación de función se deja-asociativa, es el mismo que (my_function my_foo) my_bar
, es decir, se aplica my_function
al argumento my_foo
y luego se aplica la función que se devuelve como resultado al argumento my_bar
.
Como se puede llamar así, una función del tipo foo -> bar -> baz
a menudo se denomina "una función que toma dos argumentos" y lo haré en el resto de esta respuesta.
variables de tipo
Si se define una función como let f x = x
, tendrá el tipo 'a -> 'a
. Pero 'a
no es realmente un tipo definido en la biblioteca estándar OCaml, entonces, ¿qué es?
Cualquier tipo que comience con '
es una variable de tipo llamada . Una variable de tipo puede representar cualquier tipo posible. Por lo tanto, en el ejemplo anterior, se puede llamar al f
con un int
o un string
o un list
o cualquier cosa, no importa.
Además, si la misma variable de tipo aparece en una firma de tipo más de una vez, representará el mismo tipo. Entonces, en el ejemplo anterior, eso significa que el tipo de devolución de f
es el mismo que el tipo de argumento. Por lo tanto, si se llama a f
con un int
, devuelve un int
. Si se llama con un string
, devuelve un string
y así sucesivamente.
Así que una función de tipo 'a -> 'b -> 'a
podría tomar dos argumentos de cualquier tipo (que podría no ser del mismo tipo para el primer y segundo argumento) y devolvería un valor del mismo tipo que el primer argumento, mientras que una función de tipo 'a -> 'a -> 'a
tomaría dos argumentos del mismo tipo.
Una nota sobre la inferencia de tipo: A menos que especifique explícitamente una función como una firma de tipo, OCaml siempre deducirá el tipo más general posible para usted. Entonces, a menos que una función use cualquier operación que solo funcione con un tipo dado (como +
por ejemplo), el tipo inferido contendrá variables de tipo.
Ahora, para explicar el tipo ...
val something : ('a -> 'b -> 'c) -> ('a -> 'd -> 'b) -> 'a -> 'd -> 'c = <fun>
Este tipo de firma que dice que something
es una función de tomar cuatro argumentos.
El tipo del primer argumento es 'a -> 'b -> 'c
. Es decir. una función que toma dos argumentos de tipos arbitrarios y posiblemente diferentes y devuelve un valor de un tipo arbitrario.
El tipo del segundo argumento es 'a -> 'd -> 'b
. Esta es nuevamente una función con dos argumentos. Lo importante a tener en cuenta aquí es que el primer argumento de la función debe tener el mismo tipo que el primer argumento de la primera función y el valor de retorno de la función debe tener el mismo tipo que el segundo argumento de la primera función.
El tipo del tercer argumento es 'a
, que también es el tipo de los primeros argumentos de ambas funciones.
Por último, el tipo del cuarto argumento es 'd
, que es el tipo del segundo argumento de la segunda función.
El valor de retorno será del tipo 'c
, es decir, el tipo de retorno de la primera función.
Terminología nota (que podría ayudar a sus búsquedas en la literatura): “firmas” en Ocaml por lo general significa algo más, a saber, un análogo de tipos, pero para los módulos en lugar de expresiones y valores básicos. Lo que está preguntando a veces se llama "tipo de firma", pero a menudo simplemente "escribe" o "escribe el esquema" cuando hay variables. – Gilles