OCaml
Hogere orderfuncties
Zoeken…
Syntaxis
-
val (|>) : 'a -> ('a -> 'b) -> 'b -
val (@@) : ('a -> 'b) -> 'a -> 'b
Generieke algoritmen
Hogere-orde functies kunnen worden gebruikt om generieke algoritmen te implementeren, waardoor de verantwoordelijkheid voor het verstrekken van definitieve details aan de gebruiker wordt opgelegd. List.sort verwacht bijvoorbeeld een vergelijkingsfunctie waarmee verschillende sorteermethoden kunnen worden geïmplementeerd. Hier implementeren we hoofdlettergevoelig sorteren van tekenreeksen:
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
Er is een rijke lijst van de hogere-orde functies in de standaard bibliotheek, met name in de List module, zie List.fold_left en List.sort bijvoorbeeld. Meer geavanceerde voorbeelden zijn te vinden in externe bibliotheken. Een goed voorbeeld is de gesimuleerde gloeiing geïmplementeerd in ocaml-gsl . Gesimuleerde gloeiing is een generieke optimalisatieprocedure die wordt geparametriseerd door een functie die wordt gebruikt om de set toestanden van het probleem te onderzoeken en een foutfunctie (hier energiefunctie genoemd).
Gebruikers die bekend zijn met C ++ kunnen dit vergelijken met het Strategiepatroon .
Gooi systeembronnen weg, zelfs als er een uitzondering is
Functies van een hogere orde kunnen worden gebruikt om ervoor te zorgen dat systeembronnen worden verwijderd, zelfs wanneer een behandeling een uitzondering oproept. Het patroon dat wordt gebruikt met with_output_file maakt een schone scheiding van zorgen mogelijk: de hogere-orde with_output_file functies zorgen voor het beheer van de systeembronnen die zijn gebonden aan bestandsmanipulatie, terwijl de behandeling f alleen het uitvoerkanaal verbruikt.
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)
Laten we deze functie van hogere orde gebruiken om een functie te implementeren die een string naar een bestand schrijft:
let save_string path s =
(with_output_file path) (fun c -> output_string c s)
Met behulp van meer geavanceerde functies dan fun c -> output_string cs is het mogelijk om complexere waarden op te slaan. Zie bijvoorbeeld de Marshal- module in de standaardbibliotheek of de Yojson- bibliotheek van Martin Jambon.
Samenstelling operatoren
Twee nuttige functies van hogere orde zijn de binaire applicatie ( @@ ) en reverse-applicatie of "pipe" ( |> ) operatoren. Hoewel ze sinds 4.01 beschikbaar zijn als primitieven, is het misschien nog steeds leerzaam om ze hier te definiëren:
let (|>) x f = f x
let (@@) f x = f x
Overweeg het probleem van het ophogen van het kwadraat van 3. Een manier om die berekening uit te drukken is deze:
(* 1 -- Using parentheses *)
succ (square 3)
(* - : int = 10 *)
(* where `square` is defined as: *)
let square x = x * x
Merk op dat we niet zomaar succ square 3 konden doen omdat (vanwege linkse associativiteit ) dat zou reduceren tot het betekenisloze (succ square) 3 . Met toepassing ( @@ ) kunnen we dat uitdrukken zonder haakjes:
(* 2 -- Using the application operator *)
succ @@ square 3
(* - : int = 10 *)
Merk op hoe de laatste uit te voeren bewerking (namelijk succ ) als eerste plaatsvindt in de uitdrukking? Met de operator voor omgekeerde toepassing ( |> ) kunnen we dit goed omkeren:
(* 3 -- Using the reverse-application operator *)
3 |> square |> succ
(* - : int = 10 *)
Het getal 3 wordt nu "door" square en vervolgens succ , "in plaats van toegepast op square om een resultaat te geven waarop succ wordt toegepast.