Ocaml bardzo silnie wspiera programowanie oparte o kontrakty (ang. Design by contract).
Rzeczywiście, każdy większy program w Ocamlu podzielony jest na moduły, z których każdy składa się ze specyfikacji
(czyli kontraktu, umieszczonego w pliku *.mli
) i implementacji (w pliku *.ml
).
Przykładowo, plik.mli może wyglądać tak:
type typ val wartosc : typ val operacja : typ -> typ val string_of_typ : typ -> string
Odpowiadający mu plik.ml
może wyglądać tak:
let wartosc = 7 let operacyjka x = x + 1 let operacja x = operacyjka (operacyjka x) type typ = int let string_of_typ = string_of_int
Aby sprawdzić, że implementacja spełnia swoją specyfikację, należy najpierw skompilować plik.mli
:
ocamlc -c plik.mli
O ile nie ma błędu, wyprodukowany zostanie plik.cmi
.
Teraz można skompilować plik.ml
:
ocamlc -c plik.ml
Ta komenda zakończy się powodzeniem, czyli wyprodukowaniem pliku plik.cmo
, tylko jeśli wcześniej został
skompilowany plik.mli
i implementacja rzeczywiście odpowiada specyfikacji.
Teraz w drugi_plik.ml
można skorzystać z poprzedniego modułu w następujący sposób:
let x = Plik.wartosc let y = Plik.operacja x open Plik let z = operacja y let _ = print_endline (string_of_typ z)
Zauważmy, że drugi_plik.ml
nie ma pojęcia, że typ
i int
to to samo, ani że
istnieje coś takiego, jak operacyjka
.
Istotnie, nie ma tego w specyfikacji modułu "Plik".
Aby skompilować drugi_plik.ml
należy wykonać:
ocamlc -c drugi_plik.ml
Otrzymamy plik drugi_plik.cmo
.
Aby uzyskać gotowy program wykonywalny (to tzw. linkowanie) należy wykonać:
ocamlc -o test plik.cmo drugi_plik.cmo
Teraz można sprawdzić, że działa:
./test
Co zostanie wypisane?
Wszystkie powyższe pliki można pobrać w postaci archiwum zip.
Warto w tym miejscu zapamiętać, że nazwy modułów piszemy w Ocamlu zawsze wielką literą, a nazwy
odpowiadających im plików zwyczajowo pisane są małymi literami.
Skompilowanych modułów można także używać wewnątrz interaktywnego środowiska Ocamla (tego
uruchamianego poleceniem ocaml
, lub pod emacsem
).
Przy pierwszym użyciu nazwy modułu Plik
, ładowany jest automatycznie odpowiadający mu plik.cmi
,
zawierający informacje o typach komponentów modułu.
Nie jest jednak ładowany kod samego modułu (plik.cmo
), dlatego każda próba użycia komponentów
kończy się komunikatem o błędzie:
# Plik.wartosc;; Reference to undefined global `Plik'
Plik.cmo
ładowany jest tylko na wyraźne życzenie użytkownika.
Można do tego celu użyć komendy #load
:
# #load "plik.cmo";;
Uwaga: pierwszy # (krzyżyk/hash) jest znakiem zachęty środowiska, drugi musimy wprowadzić samemu, podobnie
jak w przypadku komendy #use
czy #quit
.
Powyższa komenda dołącza skompilowany moduł Plik
do środowiska.
Po tej komendzie komponentów modułu Plik
można używać za pomocą prefiksu, np.:
Plik.string_of_typ Plik.wartosc;;
albo bez prefiksu, po uprzednim wykonaniu komendy open Plik:
open Plik;; string_of_typ wartosc;;
Można również wydać polecenie załadowania skompilowanego modułu przy starcie środowiska:
ocaml plik.cmo
Można też stworzyć własną wersję środowiska z załadowanym plikiem:
ocamlmktop plik.cmo -o moj_toplevel
I potem używać jej zamiast standardowego środowiska:
./moj_toplevel
lub
ledit ./moj_toplevel
Oczywiście w przypadku jednego modułu, z tworzenia własnej wersji środowiska nie mamy wielkiego zysku.
Załącznik | Wielkość |
---|---|
plik.mli | 90 bajtów |
plik.ml | 135 bajtów |
drugi_plik.ml | 119 bajtów |
moduly.zip | 537 bajtów |