OCaml

OCaml，是一個函式式、指令式、模組化、面向物件的通用的程式語言。在和，於1990年和1991年實現的ML方言Caml Light之上，Didier Rémy和Jérôme Vouillon，於1996年增加了面向物件特徵，從而形成了“Objective Caml”，在2011年時重新命名為“OCaml”。OCaml工具鏈包括互動式頂層直譯器、位元組碼編譯器、最佳化的本機程式碼編譯器，可逆偵錯程式和一個包管理器。OCaml最初開發於自動定理證明的場景中，並在靜態分析和形式方法軟體中有超凡的存在感。此外，它在系統程式設計、網頁程式設計和金融工程及其他應用領域都有嚴肅的應用。歷史上，Ascánder Suárez於1987年基於的。在2000年代早期，來自OCaml的元素被很多語言接納，特別是F#和Scala。哲學.ML派生語言最著稱的是靜態型別系統和型別推論編譯器。OCaml將函式式、指令式和麵向物件程式設計統一於類ML的型別系統之下。因此程式設計者不需要為了使用OCaml而非常熟悉純函數語言程式設計範型。透過要求程式設計者在靜態型別系統的約束下工作，OCaml消除了關聯於動態型別語言的很多有關於型別的執行時間問題。還有，OCaml的型別推論編譯器，極大的減少了在多數靜態型別語言中對手工型別標註的需要。例如，變數的資料型別和函式的簽名，通常不需要像Java和C#語言中那樣顯式的宣告，因為它們可以從應用於這個變數和程式碼中其他值的算符和其他函式推論出來。有效的使用OCaml的型別系統可能要求一個程式設計者面對一些複雜性，但是這種規矩能得到可靠的、高效能軟體作為回報。OCaml與源於學術界的其他語言的最顯著區別可能是強調了效能。它的靜態型別系統防止了執行時間型別不匹配，從而排除了動態型別語言執行時間型別和安全檢查的效能負擔，卻在除了關閉陣列邊界檢查，和使用一些型別不安全特徵比如序列化之外的情況下，仍能保證執行時間安全性。這些執行時間檢查需求足夠罕見，在實踐中完全可以避免。在型別檢查開銷之外，函數語言程式設計語言，要編譯成高效的機器語言程式碼，由於如這樣的要點，一般而言是具有挑戰性的。與標準的迴圈、暫存器和指令最佳化一起，OCaml的最佳化編譯器採用靜態程式分析方法，來最佳化值和閉包分配，幫助結果程式碼得到最大化的效能，即使它大量使用了函數語言程式設計構造。曾經宣稱：“OCaml至少提供了像樣的C編譯器的50%的效能”，儘管直接比較是不可能的。在OCaml標準庫中的一些函式，是採用比在其他語言標準庫中等價的函式更快的演算法實現的。例如，在OCaml標準庫中集合並集的實現，在理論上比指令式語言。特徵.OCaml的特徵包括：靜態型別系統、型別推論、引數多型、尾遞迴、模式匹配、頭等詞法閉包、函子、異常處理和增量分代自動垃圾回收。OCaml著稱於將ML風格型別推論，擴充套件到通用語言中的物件系統。這允許了，這裡的物件型別是相容的，如果它們的方法簽名是相容的，不用管它們宣告的繼承，這是在靜態型別語言中不尋常的特徵。OCaml提供了連結到C原語的，包括了兼容於C和Fortran二者格式的對高效數值陣列的語言支援。OCaml還支援建立可以連結到用C寫的codice_1程式的OCaml函式庫。OCaml發行包含了：本機程式碼編譯器可以在很多平臺上獲得，包括Unix、Microsoft Windows和Apple macOS。可移植性是透過至此主要架構的本機實現的：IA-32、X86-64、、RISC-V、ARM和ARM64。OCaml位元組碼和本機程式碼程式可以用多執行緒風格書寫，具有搶佔式上下文切換。但是由於當前唯一可得的語言完全實現INRIA OCaml的垃圾回收器，不是為併發性而設計的，對稱多處理是不支援的。在相同程序中的OCaml執行緒只能分時執行。但是有一些分散式計算庫比如Functory和Plasma。程式碼例子.OCaml的程式碼片段可以透過鍵入到頂層REPL中來很容易的研習。這是一個互動式的OCaml會話，它列印結果或定義的表示式的推論出的型別。OCaml頂層可以透過簡單執行OCaml程式來啟動：$ ocamlOCaml version 4.13.1可以接著在codice_4提示符處鍵入程式碼。例如計算codice_5:- : int = 7OCaml推論出這個表示式的型別是codice_6並給出結果codice_7。Hello World.下面的程式codice_8:print_endline "Hello World!"可以被編譯成位元組碼可執行檔案：$ ocamlc hello.ml -o hello或者被編譯成最佳化的原生代碼可執行檔案：$ ocamlopt hello.ml -o hello接著執行它：$ ./helloHello World!給ocamlc的第一個實際引數codice_8，指定要編譯的原始檔而codice_10標誌指定了輸出檔案。階乘函式.很多數學函式，比如階乘，可以很自然的表示為純粹的函式形式：let rec fact n =if n=0 then 1 else n * fact(n - 1);;這個函式可以使用模式匹配等價的寫為：let rec fact = function| 0 -&gt; 1| n -&gt; n * fact(n - 1);;後者形式是階乘作為遞推關係的數學定義。編譯器將這個函式的型別推論為codice_11，意味著這個函式將codice_6對映到codice_6。例如，codice_14：- : int = 479001600斐波那契序列.下列程式碼計算輸入數codice_15的斐波那契數列。它使用了尾遞迴和模式匹配。let fib n =let rec fib_aux m a b =match m with| 0 -&gt; a| _ -&gt; fib_aux (m - 1) b (a + b)in fib_aux n 0 1;;生日問題.下列程式計算在一個屋子裡面有完全唯一的生日機率小於50%的最少人數，在生日問題中，對於1個人這個機率是365/365，對於2個人是364/365，對於3個人是364/365 × 363/365，最終答案是23個人：let year_size = 365.let rec birthday_paradox prob people =let prob = (year_size -. float people) /. year_size *. prob inif prob  "S" ^ k) "0";;為了將一個邱奇數從函式值轉換成一個字串，這裡把它傳遞給向其輸入和常量字串codice_37前置上字串codice_38的函式codice_39：- : string = "SSSSS0"物件例子.在OCaml中物件，透過它們的方法的名字和型別，按結構來確定型別。物件可以直接建立，而不用透過有名稱的類。例如：objectval mutable x = 5method get_x = xmethod set_x y = x &lt;- yend;;val x :這裡OCaml互動式執行時間系統打印出這個物件的推論型別。它的型別codice_40，只由它的方法來定義。換句話說，codice_33的型別由方法型別codice_42和codice_43而非任何名字來定義。類只充當建立物件的函式，例如上例中的物件可以用類來定義，並接著用codice_44算符來建立：object (self)val mutable x = 5method get_x = xmethod set_x y = x &lt;- yend;;let x = new simple_cls;;要定義有相同的方法和方法型別的另一個物件：objectmethod get_x = 2method set_x y = Printf.printf "%d\n" yend;;val y :OCaml將它們視為有相同的型別。例如，等式算符被確定型別為只接受有相同型別的兩個值：- : bool = false所有儘管它們有不同的值，卻必定是相同型別的，否則連型別檢查都不會做完。這展示了型別等價是結構性的。可以定義呼叫一個方法的函式：val set_to_10 :第一個實際引數的推論型別codice_45是值得關注的。codice_46意味著第一個實際引數，可以是有接受一個codice_6作為實際引數的codice_48方法的任何物件。所以它可以用在物件codice_33之上：- : unit = ()另一個物件可以碰巧有這個方法和方法型別；其他方法是無關緊要的：objectmethod blahblah = 2.5method set_x y = Printf.printf "%d\n" yend;;val z :codice_50函式對它也有效：10- : unit = ()這展示了對於事物比如方法呼叫的相容性是由結構來確定的。下面為只有一個codice_51方法而沒有其他方法的物件定義一個型別同義詞：type simpler_obj =物件codice_33不是這個型別的；但在結構上codice_33是這個型別的一個子型別，因為codice_33包含它的方法的一個超集。所以codice_33可以強制成這個型別：- : simpler_obj =- : int = 10但是物件codice_56不行，因為它不是一個結構子型別：Error: Type  is not a subtype ofsimpler_obj =The first object type has no method get_x這展示了拓寬強制的相容性是結構性的。任意精度階乘函式.可以從OCaml訪問各種各樣的庫。比如，OCaml有內建的任意精度算術。由於階乘函式增長得非常迅速，會很快溢位機器精度的整數。因此階乘很適合選用任意精度算術。在OCaml中，codice_57模組提供了任意精度算術，比如在Ubuntu中安裝它：codice_59，它可以如下這樣裝載到執行中的頂層中：open Num;;階乘函式可以使用任意精度算符codice_60、codice_61和codice_62寫為：let rec fact n =if n =/ Int 0 then Int 1 else n */ fact(n -/ Int 1);;這個函式可以計算非常大的階乘比如codice_63：- : string ="6689502913449127057588118054090372586752746333138029810295671352301633557244962989366874165271984981308157637893214090552534408589408121859898481114389650005964960521256960000000000000000000000000000"繪製圖形例子.下列程式codice_64使用OpenGL呈現一個緩慢旋轉的2D三角形:let () =ignore (Glut.init Sys.argv);Glut.initDisplayMode ~double_buffer:true ();ignore (Glut.createWindow ~title:"OpenGL Demo");let angle t = 10. *. t *. t inlet render () =GlClear.clear [ `color ];GlMat.load_identity ();GlMat.rotate ~angle: (angle (Sys.time ())) ~z:1. ();GlDraw.begins `triangles;List.iter GlDraw.vertex2 [-1., -1.; 0., 1.; 1., -1.];GlDraw.ends ();Glut.swapBuffers () inGlMat.mode `modelview;Glut.displayFunc ~cb:render;Glut.idleFunc ~cb:(Some Glut.postRedisplay);Glut.mainLoop ()需要事先安裝負責繫結到OpenGL的LablGL，比如在Ubuntu中安裝它：codice_65，這個程式可以如下這樣編譯成位元組碼：$ ocamlc -I +lablGL lablglut.cma lablgl.cma simple.ml -o simple或編譯成本機程式碼：$ ocamlopt -I +lablGL lablglut.cmxa lablgl.cmxa simple.ml -o simple或者簡單的使用codice_66建造命令：$ ocamlfind opt simple.ml -package lablgl.glut -linkpkg -o simple然後執行：$ ./simple可以使用OCaml開發非常複雜、高效能的2D和3D圖形程式。使用OpenGL和OCaml，結果的程式可以跨平臺編譯而在主要平臺上無需改動。用OCaml寫成的程式.