Kompozitni operatori OCaml-a

2 min

U verziji 4 OCaml uvodi dva kompozitna operatora koja brzo nađu svoju primenu. Posebno je interesantno kako nešto tako jednostavno značajno doprinosi čitkijem kodu.

@@

Application operator je definisan kao:

val (@@) : ('a -> 'b) -> 'a -> 'b

Drugim rečima: g @@ f @@ x je ekvivalentno g (f (x)).

Ne, nije šala: operator je samo drugačiji oblik poziva funkcije. Čemu onda? Pregledniji kod.

Ugnježdeni pozivi nisu baš laki za praćenje - na svakoj zagradi pravimo mentalni iskorak i tražimo krajnju zagradu da bi odredili ‘oblast’ funkcije. Primer:

module StringMap = Map.Make(String);;
let m = StringMap.empty;;
let m = StringMap.(add "X" 1 (add "Y" 2 (add "Z" 3 m)));;
let m = StringMap.(add "A" 4 @@ add "B" 5 @@ add "C" 6 m);;

Poslednja dva reda dodaju elemente u mapu. Drugi način je očigledno pregledniji.

Da budem iskren, ovo neće biti operator koji ćete koristiti toliko često - ali zato sledeći hoćete!

|>

Reverse-application operator - već i ime nagoveštava - je definisan kao:

val (|>) : ‘a -> (‘a -> ‘b) -> ‘b

Drugim rečima: x |> f |> g je ekvivalentno: g (f (x)).

Ne, ni ovo nije šala - operator predstavlja inverzni oblik pozivanja funkcije. Čemu onda? Pa… služi upravo čemu i pipe operator u linuksu: rezultat se prenosi kao argument sledećeg poziva. Ovim se prilično lepo ‘razvija’ niz ugnježdenih poziva; ne samo da je kod čitljiviji, već je i lakši za razumevanje.

Primer:

let put_key_values_into_a_list c map =
 StringMap.filter (fun key _ -> String.contains key c) map
 |> StringMap.bindings
 |> List.split
 |> snd

Ovo je funkcija koja filtrira mapu, zatim izvlači sve parove, razdvaja ih na dve liste, te vraća listu vrednosti. Uočava se moć ovakvog operatora: dobija se fluent korišćenje i bez ikakvog dodatnog dizajna API-ja!

Divno je koliko su jednostavni ovi koncepti, a opet dalekosežni.

🧧
Nisam definisan svojim stavovima. Stavove usvajamo, menjamo, nadograđujemo, ali oni ne čine nas same. Manje je važno da li se slažemo, koliko da se razumemo.