OCaml

OCaml (ent. Objective Caml) on funktionaalista ja olio-ohjelmointia tukeva ohjelmointikieli. OCaml on laajennettu versio Caml-kielestä ja on sen pääasiallinen implementaatio.
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, joka käyttää "implisiittistä" tyypitystä. Kääntäjä päättelee muuttujien tyypit sen sijaan että ne määriteltäisiin lähdekoodissa.
Tästä seuraten OCaml syntaksi on hälytön, sen kääntäjä poimii virheet tehokkaasti ja tuloksena syntyvä koodi on nopeaa.
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 "let"illä 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.
type ratio = {num: int; denum: int};;
Variantit taasen luettelevat kaikki mahdolliset tyypit määrittelemälleen tietorakenteelle:
 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 -&gt; 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 -&gt; raise Queue_is_empty
 | Node(prio, elt, _, _) as queue -&gt; (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 "{&lt; ... &gt;}") ja rekursiivisiä luokkia.