OCaml
Funkcje wyższego rzędu
Szukaj…
Składnia
-
val (|>) : 'a -> ('a -> 'b) -> 'b -
val (@@) : ('a -> 'b) -> 'a -> 'b
Ogólne algorytmy
Funkcje wyższego rzędu mogą być używane do implementacji ogólnych algorytmów, rezygnując z odpowiedzialności za podanie ostatecznych szczegółów użytkownikowi. Na przykład List.sort oczekuje funkcji porównania, która pozwala zaimplementować różne sposoby sortowania. W tym przypadku implementujemy sortowanie ciągów bez rozróżniania wielkości liter:
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
W bibliotece standardowej znajduje się bogata lista funkcji wyższego rzędu, zwłaszcza w module List , patrz na przykład List.fold_left i List.sort . Bardziej zaawansowane przykłady można znaleźć w bibliotekach stron trzecich. Dobrym przykładem jest symulowane wyżarzanie zaimplementowane w ocaml-gsl . Symulowane wyżarzanie jest ogólną procedurą optymalizacji, która jest parametryzowana przez funkcję służącą do badania zestawu stanów problemu i funkcję błędu (zwaną tutaj funkcją energii).
Użytkownicy znający C ++ mogą porównać to do wzorca strategii .
Zasoby systemowe należy usuwać nawet po zgłoszeniu wyjątku
Można stosować funkcje wyższego rzędu, aby zapewnić, że zasoby systemowe są usuwane, nawet gdy leczenie stwarza wyjątek. Wzorzec używany przez with_output_file pozwala na czyste rozdzielenie obaw: funkcje wyższego rzędu with_output_file zajmują się zarządzaniem zasobami systemowymi związanymi z manipulowaniem plikami, podczas gdy leczenie f zajmuje tylko kanał wyjściowy.
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)
Użyjmy tej funkcji wyższego rzędu, aby zaimplementować funkcję zapisującą ciąg znaków do pliku:
let save_string path s =
(with_output_file path) (fun c -> output_string c s)
Używając bardziej zaawansowanych funkcji niż fun c -> output_string cs można zapisać bardziej złożone wartości. Zobacz na przykład moduł Marshal w bibliotece standardowej lub bibliotekę Yojson autorstwa Martina Jambona.
Operatorzy składu
Dwie przydatne funkcje wyższego rzędu to aplikacja binarna ( @@ ) i operatory odwrotnej aplikacji lub „potok” ( |> ). Chociaż od 4.01 są dostępne jako prymitywy, zdefiniowanie ich tutaj może być pouczające:
let (|>) x f = f x
let (@@) f x = f x
Zastanów się nad zwiększeniem kwadratu o 3. Jednym ze sposobów wyrażenia tego obliczenia jest:
(* 1 -- Using parentheses *)
succ (square 3)
(* - : int = 10 *)
(* where `square` is defined as: *)
let square x = x * x
Zauważ, że nie mogliśmy po prostu zrobić succ square 3 ponieważ (ze względu na lewostronne skojarzenie ) zredukowałoby to do bez znaczenia (succ square) 3 . Za pomocą aplikacji ( @@ ) możemy wyrazić to bez nawiasów:
(* 2 -- Using the application operator *)
succ @@ square 3
(* - : int = 10 *)
Zauważ, jak ostatnia operacja, którą należy wykonać (a mianowicie succ ), pojawia się jako pierwsza w wyrażeniu? Operator odwrotnej aplikacji ( |> ) pozwala nam odwrócić to:
(* 3 -- Using the reverse-application operator *)
3 |> square |> succ
(* - : int = 10 *)
Liczba 3 jest teraz „ succ ” przez square a następnie succ , w przeciwieństwie do nakładania na square celu uzyskania wyniku, na który stosuje się succ .