Ten artykuł od 2021-02 zawiera treści, przy których brakuje odnośników do źródeł.Należy dodać przypisy do treści niemających odnośników do źródeł. Dodanie listy źródeł bibliograficznych jest problematyczne, ponieważ nie wiadomo, które treści one uźródławiają.Sprawdź w źródłach: Encyklopedia PWN • Google Books • Google Scholar • Federacja Bibliotek Cyfrowych • BazHum • BazTech • RCIN • Internet Archive (texts / inlibrary)Dokładniejsze informacje o tym, co należy poprawić, być może znajdują się w dyskusji tego artykułu. Po wyeliminowaniu niedoskonałości należy usunąć szablon ((Dopracować)) z tego artykułu.
OCaml
logo
Paradygmat

Funkcyjny, Obiektowy, Imperatywny

Typowanie

Silne, Statyczne z inferencją

Aktualna wersja stabilna

5.2.0
(13 maja 2024) [±]

Twórca

Xavier Leroy, Damien Doligez, Jérôme Vouillon

Licencja

QPL

Platforma sprzętowa

Wieloplatformowy

Platforma systemowa

Wieloplatformowy

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:

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:

W wyniku działania kompilatorów Ocamla powstają pliki:

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:

oprócz tego występują między innymi elementy jak:

Deklaracje typów

(* 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 ();;


Zobacz publikacjęOCaml w Wikibooks

Linki zewnętrzne