OCaml
Funciones de orden superior
Buscar..
Sintaxis
-
val (|>) : 'a -> ('a -> 'b) -> 'b -
val (@@) : ('a -> 'b) -> 'a -> 'b
Algoritmos genéricos
Se pueden usar funciones de orden superior para implementar algoritmos genéricos, renunciando a la responsabilidad de proporcionar detalles finales al usuario. Por ejemplo, List.sort espera una función de comparación, que permite implementar varias formas de clasificación. Aquí implementamos la clasificación de cadenas insensibles a mayúsculas y minúsculas:
let string_case_insensitive_sort lst =
let case_insensitive_compare a b =
String.compare (String.lowercase a) (String.lowercase b)
in
List.sort case_insensitive_compare lst
Hay una lista rica de funciones de orden superior en la biblioteca estándar, especialmente en el módulo Lista , vea List.fold_left y List.sort por ejemplo. Se pueden encontrar ejemplos más avanzados en bibliotecas de terceros. Un buen ejemplo es el recocido simulado implementado en ocaml-gsl . El recocido simulado es un procedimiento de optimización genérico que está parametrizado por una función utilizada para explorar el conjunto de estados del problema y una función de error (denominada aquí función de energía).
Los usuarios familiarizados con C ++ pueden comparar esto con el patrón de Estrategia .
Disponer los recursos del sistema incluso cuando se produce una excepción
Se pueden usar funciones de orden superior para garantizar que los recursos del sistema se eliminan, incluso cuando un tratamiento genera una excepción. El patrón utilizado por with_output_file permite una clara separación de preocupaciones: las funciones de orden superior with_output_file se encargan de administrar los recursos del sistema vinculados a la manipulación de archivos, mientras que el tratamiento f solo consume el canal de salida.
let with_output_file path f =
let c = open_out path in
try
let answer = f c in
(close_out c; answer)
with exn -> (close_out c; raise exn)
Usemos esta función de orden superior para implementar una función escribiendo una cadena en un archivo:
let save_string path s =
(with_output_file path) (fun c -> output_string c s)
Usando funciones más avanzadas que fun c -> output_string cs es posible guardar valores más complejos. Vea, por ejemplo, el módulo Marshal en la biblioteca estándar o la biblioteca Yojson de Martin Jambon.
Operadores de composicion
Dos funciones útiles de orden superior son los operadores de aplicación binaria ( @@ ) y de aplicación inversa o "pipe" ( |> ). Aunque desde la versión 4.01 están disponibles como primitivas, podría ser instructivo definirlas aquí:
let (|>) x f = f x
let (@@) f x = f x
Considere el problema de incrementar el cuadrado de 3. Una forma de expresar ese cálculo es la siguiente:
(* 1 -- Using parentheses *)
succ (square 3)
(* - : int = 10 *)
(* where `square` is defined as: *)
let square x = x * x
Tenga en cuenta que no podríamos simplemente hacer succ square 3 porque (debido a la asociatividad a la izquierda ) se reduciría al significado sin sentido (succ square) 3 . Usando la aplicación ( @@ ) podemos expresar eso sin los paréntesis:
(* 2 -- Using the application operator *)
succ @@ square 3
(* - : int = 10 *)
¿Observe cómo la última operación que se realiza (es decir, succ ) ocurre primero en la expresión? El operador de aplicación inversa ( |> ) nos permite, bueno, revertir esto:
(* 3 -- Using the reverse-application operator *)
3 |> square |> succ
(* - : int = 10 *)
El número 3 ahora está "canalizado" a través del square y luego succ , en lugar de aplicarse al square para obtener un resultado al que se aplica succ .