OCaml

Historiaa

OCamlin ensiversio julkaistiin vuonna 1996 Objective Caml -nimisenä, kun Caml special light -kieleen yhdistettiin tyypitetty olio- ja luokkamalli. OCaml nimitys otettiin käyttöön vuonna 2011.

Ominaispiirteet

OCaml:ssa on korkeatasoinen tulkki ja optimoiva kääntäjä sekä laaja standardikirjasto, joka tekee siitä käyttökelpoisen myös laajojen ohjelmistojen kehitykseen.
OCaml sisältää täysiverisen olio-mallin, vahvan moduulijärjestelmän sekä polymorfisen tyyppijärjestelmän tyypinpäättelyllä. OCaml System sisältää teollisuustasoisen toteutuksen, natiivikääntäjät yhdeksälle eri prosessoriarkkitehtuurille, tavukoodikääntäjän, sekä komentorivitulkin (read-eval-loop).
OCamlin jakelu sisältää laajan standardikirjaston, debuggerin, lekseri- ja parseri-generaattorit sekä koodin tulostamiseen ja dokumentointiin tarvittavat osat. OCaml ja sen kirjastot on julkaistu avoimen lähdekoodin lisensseillä (QPL ja GGPL).
OCamlia ei ole standardoitu, vaan kuten esimerkiksi Python, OCamlilla on kielen määrittelevä toteutus, INRIA:n OCaml.

Esimerkki OCamlin käytöstä

Tyypillinen esimerkkiohjelma hello.ml tulostaa sanat "Hello World":

  
  print_endline "Hello world!";;

OCamlissa ohjelma käännetään komennolla:

  
  $ ocamlc -o hello_ocaml hello.ml

Ohjelman ajaminen:

  
  $ ./hello_ocaml

  Hello world!

OCaml kielenä

OCaml on kypsä ML-sukuinen funktionaalinen olio-ohjelmointikieli. Se on kirjoitettu OCamlilla itsellään lukuun ottamatta joitakin C-kielellä kirjoitettuja ajonaikaisia osia. OCaml perii paljon vuosikymmenien funktionaalisten kieliin, kielentutkimukseen ja tyyppiteoriaan liittyvästä akateemisesta tutkimustyöstä. OCamlia käytetään sekä opetuskielenä, että teollisuudessa.
OCaml on staattisesti tyypitetty kieli. Tyyppimäärittelyt ovat valinnaisia: yleensä kääntäjä päättelee arvojen tyypit sen sijaan että ne määriteltäisiin lähdekoodissa. Vahvasti tyypitettynä kielenä se estää muistinhallintavirheitä tehokkaasti.
Tästä seuraten OCaml syntaksi on hälytön, sen kääntäjä poimii virheet tehokkaasti, ja tuloksena syntyvä koodi on nopeaa – OCaml on tehokas kieli.

Syntaksi

OCamlissa on ML:stä periytynyt  suoraviivainen syntaksi. Sen ytimekäs syntaksi ilmaisee lambda-kalkyylia kolmella tavalla: tunnistimet (esim. x), funktiot (λ x. a) ja sovelmat (a1 a2). Lisäksi löytyy let -lause (esim let x = a1 in a2), jota käytetään sitomaan ilmaisu a1 tunnistimeen x ilmaisussa a2.

Fraasit

Ocamlissa yksittäinen lauseke on muodoltaan Caml-fraasi. Fraasit ovat joko ilmaisuja tai tunnistimien let-määritelmiä. Komentotulkkia käytettäessä ne päättyvät ';;' merkkeihin, jotka eivät ole välttämättömiä kieltä käännettäessä.

  
  1 + 2 * 4;;

  let piiarvo = 4.0 *. atan 1.0;; (* huomaa oma kertomaoperaattori liukuluvuille *)
Kullekin fraasille lasketaan kääntäjässä arvo ja tyyppi, eikä tyyppiä tarvitse erikseen määritellä.
Tyyppien päättely mahdollistaa polymorfisuuden funktioille.

Tyyppijärjestelmä

OCamlin tyyppijärjestelmästä löytyvät tyypit totuusarvo (boolean), kokonaisluku, liukuluku, merkki ja merkkijono.

Tietorakenteet

Ennaltamääritellyt tietorakenteet ovat monikko (tuple), taulukko (array) ja lista (list). Useimmat OCamlin tietorakenteet ovat muuttumattomia, mutta taulukko on muuttuva - sen kokoa voi muuttaa sen määrittelemisen jälkeenkin. Monikot ja listat voivat sisältää tyypeiltään eriäviä arvoja, kun taulukko sisältää samantyyppisiä arvoja.
OCamlissa ei ole muuttujan käsitettä. OCaml Standard library -kirjasto sisältää viitteet (references), yhden alkion taulut joita letillä tunnistimiin sitomalla voi viitata vaihteleviin arvoihin.
Käyttäjän määrittelemät tietorakenteet ovat taltiot (records) ja variantit (variants). Taltiot kuvaavat tietorakenteen osaset ja niiden tyypit.
(* taltio eli record määritellään murtoluvuille näin: *)type ratio = {num: int; denum: int};;

Variantit taasen luettelevat kaikki mahdolliset tyypit määrittelemälleen tietorakenteelle:
(* variant määritellään numeroille näin: *)

  type number = Int of int | Float of float | Error;;

OCaml ja funktiot

OCaml on funktionaalinen ohjelmointikieli – se tukee funktioita matemaattisen määritelmän mukaisesti täysin. Tästä seuraten funktioita voi vapaasti antaa parametreinä ja käyttää kuten muitakin tietotyyppejä. OCaml tukee myös korkeamman asteen funktioita (higher order functions), eli funktioita joihin annetaan toisia funktioita argumentteina.
  List.map (function n -> n * 2 + 2) [0;1;2;3;4];;
  - : int list = [2; 4; 6; 8; 10]

Funktiot ja rekursio

OCaml tukee rekursiota. Rekursio ilmaistaan käyttäen rec-sanaa. Rekursion käyttö on rajoitettu funktioihin, koska sen todistus ei ole eheä mielivaltaisille ilmaisuille.
 let  rec  f = λ x. a1  in  a2

 (** tai esimerkiksi **)

 let  rec  f1 = λ x. a1  and  f2 = λ x. a2  in  a

Imperatiiviset piirteet

OCamlin imperatiivisiin ominaisuuksiin kuuluvat for ja while -silmukat, sekä muuntuvat tietorakenteet kuten taulukot (array). Myös taltiot voivat olla muuntuvia, jos ne määritellään käyttämällä avainsanaa mutable.

Poikkeukset

OCaml tukee ohjelmien poikkeustilaa ja niiden käsittelyä. Poikkeuskäsittelijä määritellään exception avainsanalla.

Muistinhallinta

OCamlin muistinhallinta on täysin automaattinen - kääntäjä osaa käyttää osoittimia (pointers) ja ajaa roskienkeräyksen tarvittaessa.

OCamlin moduulijärjestelmä

OCaml käyttää moduuleita johdonmukaisen rakenteen ja yhtenäisen nimikäytännön aikaansaamiseksi. OCamlissa tällaisia rakenteita (structure) määritellään lauseella struct ... end, jonka sisäpuolella voi olla mielivaltaisia lausekesarjoja. Rakenteelle annetaan yleensä myös nimi sitomalla se tunnistimeen module -avainsanalla. Näin estetään nimien loppuminen ja törmäily nimiavaruudessa.

 
 module PrioQueue =  
   struct
     type priority = int
     (** jne... **)
     let extract = function
         Empty -> raise Queue_is_empty
       | Node(prio, elt, _, _) as queue -> (prio, elt, remove_top queue)
   end;;

Moduulijärjestelmä mahdollistaa myös tyyppiabstraktion (abstract types). Määritellyn tietorakenteen osien näkyvyyttä voi määritellä kuvaajalla(sic) (signature), joka määritellään avainsanoilla sig ... end.
OCamlin moduulijärjestelmän avulla voi myös määritellä funktoreita. Funktorit ovat yksinkertaisesti yhden rakenteen avulla parametrisoituja rakenteita; rakenne A joka määritellään rakenteen B:n avulla voidaan sanoa olevan funktori F parametrillä B joka palauttaa rakenteen A. Myös funktoreihin voi soveltaa kuvaajaa (signature).
OCamlin moduuliominaisuudet mahdollistavat myös monista moduuleista koostuvan ohjelman osien kääntämisen eri aikaan .ml rakennetiedostojen ja .mli kuvaajien lähdekoodista .cmo-objekti- ja .cmi-rajapintatiedostoiksi, jotka lopulta yhdistetään konekielikäännökseksi.

OCamlin oliomalli

OCamlin oliomalli on omintakeinen. OCamlin luokat (class) määrittelevät olioita (object) käyttäen periytyvyyttä ja metodeita.

Oliot

Olioiden tyypitys on tavallinen, ja niillä voi lisäksi olla alatyyppejä. Oliot eivät tunne periytymistä.
Oliot luodaan yleensä luokista, käyttäen new -avainsanaa. Oliot voidaan myös luoda kloonaamalla (metodilla Oo.copy) tai kaappaamalla (overriding) toisia olioita.
Olioita voidaan myös määritellä ilman luokkia, välittöminä objekteina (immediate objects). Tällöin oliota kuvaus (object ... end) voi esiintyä missä vain ekspressiossa, mutta tuloksena syntyvä olio ei omaa luokkien ominaisuuksia, kuten periytyvyys.
Olioiden sisältämät, niiden luokissa määritellyt tietorakenteet ovat saatavilla vain olioiden metodien kautta (enkapsulaatio). OCaml ei tunne luokkamuuttujia, eli kullakin oliolla on omat yksittäiset tietorakennejoukkonsa. Tässä mielessä OCamlin oliomalli noudattaa klassista olio-ohjelmointi-mallia.

Luokat

Luokat ovat OCamlissa yleisen olio-ohjelmointi-paradigman mukaisesti määritelmiä olioiden rakentamista varten. OCaml -luokilla on oma, tavallisista tyypeistä poikkeava tyyppijärjestelmänsä, ja luokat voivat periytyä toisista luokista. Luokat määritellään OCamlissa sitomalla luokka ja sen nimi oliorakenteeseen class NN object ... end -rakenteella.

Periytyvyys

Luokkia voidaan periyttää toisista luokista lisäämällä object ... end-rakenteen sisään inherit NN -viittaus. OCaml tukee moninperiytyvyyttä.
Luokkien metodit määritellään puolestaan samaisen object-rakenteen sisällä method nn = ... ilmaisuilla. Luokkien metodimääritelmät ovat varjostavia, eli jälkeläisen metodi korvaa vanhemmalta perityn metodin. Tätä kutsutaan OCamlissa nimellä late binding. Esi-isä-luokan metodeita voidaan kuitenkin sitoa vaihtoehtoisiin metodinimiin käyttäen avainsanaa super.

Alustus, näkyvyyden rajoittaminen ja virtuaaliluokat

OCaml luokat tukevat niistä olioita luotaessa kutsuttavia alustusmetodeita. Alustusmetodit ovat avainsanalla initializer määriteltäviä anonyymejä metodeita, joita ei voi varjostaa tai uudelleenmääritellä. Periytetyissä luokissa alustusmetodit ajetaan määrittelyjärjestyksessä. 
OCaml-luokkien metodit voivat olla yksityisiä, jolloin ne eivät näy olion ulkopuolella, ja niitä voidaan kutsua vain toisista saman olion metodeista. Yksityiset metodit määritellään ilmaisulla method private. OCamlin yksityiset metodit ovat vain saman olio-instanssin käytettävissä, joten ne eroavat tässä suhteessa C++:n yksityisistä metodeista, jotka ovat saman luokan olio-instanssien käytettävissä.
OCaml luokat voivat myös olla virtuaalisia; luokkia joissa määritellään virtuaalisia, sisällöttömiä metodeita ja instanssimuuttujia (virtual). Virtuaalisien luokkien virtuaaliset metodit ja muuttujat täytyy määritellä aliluokassa ennen kuin niistä voidaan instantioida olioita.
Virtuaaliset metodit voivat olla yksityisiä, syntaksissa tämä tapaus ilmaistaan method private virtual.

Muut luokkaominaisuudet

Tavallisten olio-ohjelmointimallien lisäksi OCaml tukee myös parametrisoituja luokkamääritelmiä, polymorfisia metodeita, tyypinpakotusta (coercion), funktionaalisia objekteja (syntaksissa {< ... >}) ja rekursiivisiä luokkia.