[go: nahoru, domu]

Przejdź do zawartości

OCaml: Różnice pomiędzy wersjami

Z Wikipedii, wolnej encyklopedii
[wersja przejrzana][wersja przejrzana]
Usunięta treść Dodana treść
Bidoofpl (dyskusja | edycje)
Funkcja sugerowania linków: dodany 1 link.
 
Linia 47: Linia 47:
''Uwaga: Informacje te odnoszą się do systemów [[Unix|uniksowych]]. W innych systemach niektóre czynności należy wykonywać w inny sposób.''
''Uwaga: Informacje te odnoszą się do systemów [[Unix|uniksowych]]. W innych systemach niektóre czynności należy wykonywać w inny sposób.''


Pliki źródłowe ocamla mają rozszerzenie <tt>ml</tt>, pliki z sygnaturami – odpowiednik plików nagłówkowych w C – rozszerzenie <tt>mli</tt>. Nie ma tu jednak żadnego preprocesora i literalnego włączania nagłówków – pliki sygnaturowe są najzwyczajniej kompilowane.
Pliki źródłowe ocamla mają rozszerzenie <code>ml</code>, pliki z sygnaturami – odpowiednik plików nagłówkowych w C – rozszerzenie <code>mli</code>. 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 <tt>ml</tt>.
Zwykle nie ma potrzeby tworzenia osobnych plików sygnaturowych i OCaml automatycznie generuje sygnatury na podstawie plików <code>ml</code>.


Istnieją trzy sposoby wykonywania programów napisanych w języku '''OCaml''':
Istnieją trzy sposoby wykonywania programów napisanych w języku '''OCaml''':
* za pomocą interpretera – komenda <tt>ocaml</tt>. Dogodne do pisania prostych skryptów czy testowania.
* za pomocą interpretera – komenda <code>ocaml</code>. Dogodne do pisania prostych skryptów czy testowania.
* kompilacja do binarnej postaci interpretowanej – komenda <tt>ocamlc</tt>. 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 (informatyka)|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 binarnej postaci interpretowanej – komenda <code>ocamlc</code>. 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 (informatyka)|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 <tt>ocamlopt</tt>. Tworzy bardzo szybki program, który nie wymaga żadnych zewnętrznych bibliotek oprócz [[Biblioteka standardowa języka C|libc]].
* kompilacja do kodu maszynowego – komenda <code>ocamlopt</code>. Tworzy bardzo szybki program, który nie wymaga żadnych zewnętrznych bibliotek oprócz [[Biblioteka standardowa języka C|libc]].


W wyniku działania kompilatorów Ocamla powstają pliki:
W wyniku działania kompilatorów Ocamla powstają pliki:
* <tt>cmi</tt> – skompilowane pliki sygnaturowe, takie same w <tt>ocamlc</tt> i <tt>ocamlopt</tt>
* <code>cmi</code> – skompilowane pliki sygnaturowe, takie same w <code>ocamlc</code> i <code>ocamlopt</code>
* <tt>cmo</tt> – pliki obiektów dla <tt>ocamlc</tt>
* <code>cmo</code> – pliki obiektów dla <code>ocamlc</code>
* <tt>cma</tt> – bibliotek dla <tt>ocamlc</tt>
* <code>cma</code> – bibliotek dla <code>ocamlc</code>
* <tt>o</tt> – zwykłe pliki obiektowe, tworzone przez <tt>ocamlopt</tt>
* <code>o</code> – zwykłe pliki obiektowe, tworzone przez <code>ocamlopt</code>
* <tt>cmx</tt> – pliki obiektowe z dodatkowymi informacjami na temat modułów służące do optymalizacji, tworzone przez <tt>ocamlopt</tt>.
* <code>cmx</code> – pliki obiektowe z dodatkowymi informacjami na temat modułów służące do optymalizacji, tworzone przez <code>ocamlopt</code>.
* <tt>cmxa</tt> – biblioteki dla <tt>ocamlopt</tt>.
* <code>cmxa</code> – biblioteki dla <code>ocamlopt</code>.


* pliki wykonywalne (bez rozszerzenia):
* pliki wykonywalne (bez rozszerzenia):
** pliki skryptowe [[shebang]] <tt>ocamlrun</tt> generowane przez <tt>ocamlc</tt>
** pliki skryptowe [[shebang]] <code>ocamlrun</code> generowane przez <code>ocamlc</code>
** binarne pliki wykonywalne (na [[Linux|Linuksie]] typu [[Executable and Linkable Format|ELF]]) generowane przez <tt>ocamlopt</tt>
** binarne pliki wykonywalne (na [[Linux|Linuksie]] typu [[Executable and Linkable Format|ELF]]) generowane przez <code>ocamlopt</code>


== System typów ==
== System typów ==
Linia 92: Linia 92:
oprócz tego występują między innymi elementy jak:
oprócz tego występują między innymi elementy jak:


* komentarze między <tt>(*</tt> i <tt>*)</tt> które mogą być zagnieżdżone
* komentarze między <code>(*</code> i <code>*)</code> które mogą być zagnieżdżone
* stałe stringów które mogą być kilkuliniowe
* stałe stringów które mogą być kilkuliniowe
* stałe list
* stałe list
Linia 143: Linia 143:
</syntaxhighlight>
</syntaxhighlight>


==== <tt>int</tt> ====
==== <code>int</code> ====
Czyli liczby całkowite.
Czyli liczby całkowite.
Operacje na nich to m.in. <tt>+</tt>, <tt>-</tt>, <tt>*</tt>, <tt>/</tt>.
Operacje na nich to m.in. <code>+</code>, <code>-</code>, <code>*</code>, <code>/</code>.


<syntaxhighlight lang="ocaml">
<syntaxhighlight lang="ocaml">
Linia 152: Linia 152:
</syntaxhighlight>
</syntaxhighlight>


==== <tt>float</tt> ====
==== <code>float</code> ====
Liczby zmiennoprzecinkowe mają osobny zestaw operacji, co zmniejsza znacznie czytelność, ale jest konieczne ze względu na sposób działania systemu [[inferencja typów|inferencji typów]].
Liczby zmiennoprzecinkowe mają osobny zestaw operacji, co zmniejsza znacznie czytelność, ale jest konieczne ze względu na sposób działania systemu [[inferencja typów|inferencji typów]].


Operacje te zwykle kończą się kropką, np. <tt>+.</tt>, <tt>-.</tt>, <tt>*.</tt>, <tt>/.</tt>.
Operacje te zwykle kończą się kropką, np. <code>+.</code>, <code>-.</code>, <code>*.</code>, <code>/.</code>.


<syntaxhighlight lang="ocaml">
<syntaxhighlight lang="ocaml">
Linia 162: Linia 162:
</syntaxhighlight>
</syntaxhighlight>


==== <tt>char</tt> ====
==== <code>char</code> ====
Pojedyncze znaki umieszcza się w pojedynczym cudzysłowie:
Pojedyncze znaki umieszcza się w pojedynczym cudzysłowie:


Linia 170: Linia 170:
</syntaxhighlight>
</syntaxhighlight>


Do zamieniania znaków na ich wartości numeryczne i na odwrót służą <tt>int_of_char</tt> oraz <tt>char_of_int</tt>.
Do zamieniania znaków na ich wartości numeryczne i na odwrót służą <code>int_of_char</code> oraz <code>char_of_int</code>.


==== <tt>string</tt> ====
==== <code>string</code> ====
Łańcuchy tekstowe umieszcza się w podwójnym cudzysłowie:
Łańcuchy tekstowe umieszcza się w podwójnym cudzysłowie:


Linia 180: Linia 180:
</syntaxhighlight>
</syntaxhighlight>


=== <tt>bool</tt> ===
=== <code>bool</code> ===
Wartości logiczne – <tt>true</tt> i <tt>false</tt>.
Wartości logiczne – <code>true</code> i <code>false</code>.
Operacje to <tt>not</tt>, <tt>||</tt>, <tt>&&</tt> itd.
Operacje to <code>not</code>, <code>||</code>, <code>&&</code> itd.


=== <tt>unit</tt> ===
=== <code>unit</code> ===
Typ pusty, wartość tylko <tt>()</tt>.
Typ pusty, wartość tylko <code>()</code>.


Oraz na typach pochodnych takich jak:
Oraz na typach pochodnych takich jak:


==== Listy elementów danego typu ====
==== Listy elementów danego typu ====
Lista elementów danego typu to <tt>'a list</tt>, np. <tt>[1; 2; 3]</tt> to lista typu <tt>int list</tt>, a <tt>[2.71; 3.14; 6.28]</tt> to lista typu <tt>float list</tt>.
Lista elementów danego typu to <code>'a list</code>, np. <code>[1; 2; 3]</code> to lista typu <code>int list</code>, a <code>[2.71; 3.14; 6.28]</code> to lista typu <code>float list</code>.


==== Krotka ====
==== Krotka ====
Krotka to zestaw ustalonej liczby wartości o przyporządkowanych im na stałe, lecz niekoniecznie tych samych, typach zmiennych.
Krotka to zestaw ustalonej liczby wartości o przyporządkowanych im na stałe, lecz niekoniecznie tych samych, typach zmiennych.
Krotką jest np. para (<tt>2, "napis"</tt>), czy trójka (<tt>3, 2, 3.14</tt>).
Krotką jest np. para (<code>2, "napis"</code>), czy trójka (<code>3, 2, 3.14</code>).
Branie krotek w nawiasy nie jest konieczne, lecz zwiększa czytelność programu.
Branie krotek w nawiasy nie jest konieczne, lecz zwiększa czytelność programu.


Linia 201: Linia 201:
Jeśli potrzebny jest konstruktor, który przyjmuje więcej niż jeden parametr, używa się krotki.
Jeśli potrzebny jest konstruktor, który przyjmuje więcej niż jeden parametr, używa się krotki.


Na przykład zdefiniujmy typ <tt>foo</tt> mający dwa konstruktory – <tt>Foo</tt> o parametrze <tt>int</tt> i <tt>Bar</tt> o parametrze <tt>string</tt>:
Na przykład zdefiniujmy typ <code>foo</code> mający dwa konstruktory – <code>Foo</code> o parametrze <code>int</code> i <code>Bar</code> o parametrze <code>string</code>:
<syntaxhighlight lang="ocaml">
<syntaxhighlight lang="ocaml">
type foo = Foo of int | Bar of string;;
type foo = Foo of int | Bar of string;;
Linia 214: Linia 214:
</syntaxhighlight>
</syntaxhighlight>


Przykładem predefiniowanej polimorficznej alternatywy jest typ <tt>'a option</tt>.
Przykładem predefiniowanej polimorficznej alternatywy jest typ <code>'a option</code>.
Np. dla typu <tt>int option</tt> poprawnymi wartościami są <tt>None</tt> i <tt>Some 4</tt>.
Np. dla typu <code>int option</code> poprawnymi wartościami są <code>None</code> i <code>Some 4</code>.


== Przykładowy kod ==
== Przykładowy kod ==

Aktualna wersja na dzień 01:06, 14 cze 2024

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

[edytuj | edytuj kod]

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

[edytuj | edytuj kod]

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):
    • pliki skryptowe shebang ocamlrun generowane przez ocamlc
    • binarne pliki wykonywalne (na Linuksie typu ELF) generowane przez ocamlopt

System typów

[edytuj | edytuj kod]

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

[edytuj | edytuj kod]

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

[edytuj | edytuj kod]
  • 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

[edytuj | edytuj kod]

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 }

Czyli liczby całkowite. Operacje na nich to m.in. +, -, *, /.

let x = 2 + 2 * 2;;
print_int x;;

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;;

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

[edytuj | edytuj kod]

Łańcuchy tekstowe umieszcza się w podwójnym cudzysłowie:

let s = "Ala ma kota\n";;
print_string s;;

Wartości logiczne – true i false. Operacje to not, ||, && itd.

Typ pusty, wartość tylko ().

Oraz na typach pochodnych takich jak:

Listy elementów danego typu

[edytuj | edytuj kod]

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

[edytuj | edytuj kod]

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

[edytuj | edytuj kod]

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

[edytuj | edytuj 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

[edytuj | edytuj kod]