OCaml
Ten artykuł od 2021-02 zawiera treści, przy których brakuje odnośników do źródeł. |
Paradygmat | Funkcyjny, Obiektowy, Imperatywny |
---|---|
Typowanie | Silne, Statyczne z inferencją |
Aktualna wersja stabilna | 4.14.0 |
Twórca | Xavier Leroy, Damien Doligez, Jérôme Vouillon |
Licencja | QPL |
Platforma sprzętowa | |
Platforma systemowa | |
Strona internetowa |
OCaml (wcześniej jako Objective Caml) – wieloparadygmatowy język programowania oraz implementacja tego języka w postaci zestawu narzędzi i bibliotek. Jest, oprócz Caml Light, główną implementacją języka Caml. OCaml został stworzony przez Xaviera Leroya, Jérôme Vouillon, Damien Doligeza, Didier Rémy i innych w 1996 roku, kiedy to Caml Light został poszerzony o system obiektów i natywny kompilator.
OCaml wspiera równie dobrze programowanie funkcyjne, obiektowe, jak i imperatywne.
Nadaje się do pisania dużych programów przemysłowych ze względu na silny system modułów, dostępne programowanie obiektowe, szybki natywny kompilator oraz szczególnie dobre wsparcie dla programowania funkcyjnego.
Jest wolnym oprogramowaniem tworzonym we francuskim akademickim instytucie badawczym INRIA.
OCaml wywodzi się z rodziny języków Meta Language, podobnie jak Standard ML.
Programy napisane w Ocamlu zajmują czołowe miejsca w ICFP Programming Contest.
Narzędzia
OCaml składa się z następujących narzędzi:
- ocaml – interpreter (tzw. REPL) pozwalający na interaktywne wpisywanie wyrażeń i konstrukcji języka.
- ocamlc – kompilator do bytecodu. Pozwala na pisanie przenośnych programów, które jednak są wolniejsze niż programy skompilowane natywnym kompilatorem.
- ocamlrun – interpreter bytecodu i system runtime. Pozwala na wykonanie pliku skompilowanego przez ocamlc.
- ocamlopt – optymalizujący, natywny kompilator. Generuje bardzo szybki kod na wiele platform.
- ocamldep – analizator zależności między modułami. Głównym zadaniem jest tworzenie plików zawierających informacje o zależnościach dla innych narzędzi.
- ocamldoc – generator dokumentacji do bibliotek, podobny do Doxygena dla C/C++. Wszystkie biblioteki dostępne do OCamla powinny mieć dokumentację API utworzoną za pomocą tego narzędzia.
- ocamlbuild – program pomocny do budowania całych projektów.
- ocamllex – generator analizatorów leksykograficznych.
- ocamlyac – generator parserów LALR(1).
- ocamlcp – profiler, pomocny przy analizie szybkości działania programów.
- camlp4 – pre-procesor programów napisanych w OCamlu. Pozwala na poszerzanie składni, generację i analizę kodu w OCamlu. Operuje bezpośrednio na drzewie składni.
- ocamlfind – manager bibliotek. Umożliwia wygodne zarządzanie instalacją pakietów. Mimo że nie występuje w standardowej dystrybucji OCamla jest zaliczany do jednych z ważniejszych narzędzi.
Używanie Ocamla z poziomu powłoki
Uwaga: Informacje te odnoszą się do systemów uniksowych. W innych systemach niektóre czynności należy wykonywać w inny sposób.
Pliki źródłowe ocamla mają rozszerzenie ml, pliki z sygnaturami – odpowiednik plików nagłówkowych w C – rozszerzenie mli. Nie ma tu jednak żadnego preprocesora i literalnego włączania nagłówków – pliki sygnaturowe są najzwyczajniej kompilowane.
Zwykle nie ma potrzeby tworzenia osobnych plików sygnaturowych i OCaml automatycznie generuje sygnatury na podstawie plików ml.
Istnieją trzy sposoby wykonywania programów napisanych w języku OCaml:
- za pomocą interpretera – komenda ocaml. Dogodne do pisania prostych skryptów czy testowania.
- kompilacja do binarnej postaci interpretowanej – komenda ocamlc. Program ten przetwarza kod źródłowy na byte code który może zostać uruchomiony przez system uruchomieniowy zawierający również interpreter. Instrukcje są podobne do wielu innych wirtualnych maszyn (jak JVM, .NET czy Dalvik) poza faktem że odbywa się bezpośrednia interpretacja, a nie translacja w locie (tzw. JIT). ocamlrun to narzędzie który wykonuje instrukcje zapisane w pliku wykonywalnym. Pliki binarne są agnostyczne względem platformy, dlatego głównym ich zastosowaniem jest tzw. bootstrapowanie samego kompilatora OCamla.
- kompilacja do kodu maszynowego – komenda ocamlopt. Tworzy bardzo szybki program, który nie wymaga żadnych zewnętrznych bibliotek oprócz libc.
W wyniku działania kompilatorów Ocamla powstają pliki:
- cmi – skompilowane pliki sygnaturowe, takie same w ocamlc i ocamlopt
- cmo – pliki obiektów dla ocamlc
- cma – bibliotek dla ocamlc
- o – zwykłe pliki obiektowe, tworzone przez ocamlopt
- cmx – pliki obiektowe z dodatkowymi informacjami na temat modułów służące do optymalizacji, tworzone przez ocamlopt.
- cmxa – biblioteki dla ocamlopt.
- pliki wykonywalne (bez rozszerzenia):
System typów
Jądro systemu typów opiera się na polimorficznie typowanym rachunku lambda z inferencją typów algorytmem unifikacji Hindley-Milner.
OCaml jest silnie typowanym językiem.
Nie dopuszcza żadnych automatycznych konwersji, czy przeciążania funkcji czy nawet przeciążonych operatorów infix dla różnych typów numerycznych.
Zaletą tego jest że algorytm inferencji jest prosty i efektywny, wadą natomiast jest czasem użycie, gdzieniegdzie, pomocniczych funkcji – co w praktyce nie jest problemem i kod w OCamlu zazwyczaj i tak jest bardziej zwięzły niż w innych językach.
Inne języki funkcyjne, jak Haskell, posiadają mechanizm przeciążania przez tzw. type classes – które pełnią podobne role jak moduły i funktory w OCamlu. Umożliwia to inferencje typów wraz z udogodnieniami przeciążania, z umiarkowaną ceną dodatkowych adnotacji sygnatur funkcji.
Własnością bazowego system typów jest brak wymogu jakichkolwiek adnotacji. Adnotacje natomiast występują w celu generacji dokumentacji przez ocamldoc bądź przy bardziej zaawansowanych użyciach systemu wychodzącego poza pierwotny system typów ML, jak funktory, obiekty, moduły opakowane, polimorficzna rekursja czy GADTs.
Składnia
Syntaktycznie bazowy język OCaml ma bardzo prostą, zwięzłą, ale zarazem bardzo praktyczną składnie składającą się z następujących komponentów:
- definicje typów
- definicje wartości
- definicje modułów
- deklaracje typów i wartości w sygnaturach modułów
- adnotacje typów
oprócz tego występują między innymi elementy jak:
- komentarze między (* i *) które mogą być zagnieżdżone
- stałe stringów które mogą być kilkuliniowe
- stałe list
- stałe tablic
Deklaracje typów
- deklaracja typów przez słowo kluczowe type – w przeciwieństwie do Standard ML, OCaml nie ma rozróżnienia między deklaracjami nowych typów a algebraicznymi typami (przez datatype w SML), przykłady:
(* Aliasy typu *)
type numer = int
type para = string * int
type lista_int = int list
(* Rekord *)
type punkt = { x : float; y : float }
(* Rekord polimorficzny *)
type ('a, 'b) nazwana_para = { first : 'a; second : 'b }
(* Warianty, czy alternatywy (polimorficzne) *)
type 'a drzewo =
Drzewo of 'a drzewo * 'a drzewo
| Lisc of 'a
(* Typ abstrakcyjny *)
type abstrakcyjny
Jak widać typy mogą być polimorficzne, czyli mogą być parametryzowane przez inny typ poprzez zmienne typu (jak w przykładzie 'a albo 'b). Zmienna typu zostanie podstawiona automatycznie przez inferencje typów.
Definicje wartości
Wartości są definiowane przez konstrukcje let która nadaje nazwę wartości czyniąc ją zmienną.
(* Globalna wartosc *)
let numer = 42
(* Definicje tej samej funkcji *)
let dodaj x y = x + y
let dodaj = fun x y -> x + y
let dodaj = fun x -> fun y -> x + y
(* Bardziej skomplikowana funkcja, zmienne lokalne *)
let pitagoras p1 p2 =
let roznica = { x = p2.x - p1.x; y = p2.y - p1.y } in
roznica.x * roznica.x + roznica.y * roznica.y
(* Definicja instancji drzewa *)
let drzewo = Drzewo (Drzewo (Lisc 1, Lisc 2), Lisc 3)
(* Lista *)
let lista_int = [1;2;3;4;5;6]
(* Rekord *)
let punkt = { x = 1.; y = 2. }
(* Polimorficzny rekord *)
let nazwana_para = { first = 1.0; second = "Ala ma kota" }
let nazwana_para = { first = [1;2;3]; second = 42 }
int
Czyli liczby całkowite. Operacje na nich to m.in. +, -, *, /.
let x = 2 + 2 * 2;;
print_int x;;
float
Liczby zmiennoprzecinkowe mają osobny zestaw operacji, co zmniejsza znacznie czytelność, ale jest konieczne ze względu na sposób działania systemu inferencji typów.
Operacje te zwykle kończą się kropką, np. +., -., *., /..
let y = 2.0 +. 2.0 *. 2.0;;
print_float y;;
char
Pojedyncze znaki umieszcza się w pojedynczym cudzysłowie:
let c = '\n';;
print_char c;;
Do zamieniania znaków na ich wartości numeryczne i na odwrót służą int_of_char oraz char_of_int.
string
Łańcuchy tekstowe umieszcza się w podwójnym cudzysłowie:
let s = "Ala ma kota\n";;
print_string s;;
bool
Wartości logiczne – true i false. Operacje to not, ||, && itd.
unit
Typ pusty, wartość tylko ().
Oraz na typach pochodnych takich jak:
Listy elementów danego typu
Lista elementów danego typu to 'a list, np. [1; 2; 3] to lista typu int list, a [2.71; 3.14; 6.28] to lista typu float list.
Krotka
Krotka to zestaw ustalonej liczby wartości o przyporządkowanych im na stałe, lecz niekoniecznie tych samych, typach zmiennych. Krotką jest np. para (2, "napis"), czy trójka (3, 2, 3.14). Branie krotek w nawiasy nie jest konieczne, lecz zwiększa czytelność programu.
Alternatywy
Alternatywa to zestaw konstruktorów, które mogą być parametryzowane (wtedy typ ma podwartości równe wszystkim możliwym wartościom parametru) bądź też nie (istnieje tylko jedna wartość z takim konstruktorem). Jeśli potrzebny jest konstruktor, który przyjmuje więcej niż jeden parametr, używa się krotki.
Na przykład zdefiniujmy typ foo mający dwa konstruktory – Foo o parametrze int i Bar o parametrze string:
type foo = Foo of int | Bar of string;;
let print_foo = function
Foo n -> print_int n
| Bar s -> print_string s
;;
print_foo (Foo 2);;
print_foo (Bar "Napis")
Przykładem predefiniowanej polimorficznej alternatywy jest typ 'a option. Np. dla typu int option poprawnymi wartościami są None i Some 4.
Przykładowy kod
(* komentarz *)
let rec fib n =
if n < 2
then n
else fib (n-1) + fib (n-2)
;;
(* inny sposób, wykorzystujący dopasowanie do wzorca *)
let rec fibb = function
| 0 -> 0
| 1 -> 1
| n -> fibb (n-1) + fibb(n-2)
;;
print_string "Hello, world !\n";;
print_int (fib (2+2*2));;
print_newline ();;
Linki zewnętrzne
- Anglojęzyczny portal z bogatym źródłem informacji
- „Developing Applications With Objective Caml” – książka na temat Ocamla dostępna w sieci. caml.inria.fr. [zarchiwizowane z tego adresu (2002-12-20)].
- The Caml language
- Caml Development Kit. pauillac.inria.fr. [zarchiwizowane z tego adresu (2002-10-04)].