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 |