Pemrograman · Bahasa pemrograman
Tutorial OCaml untuk pemula
Jawaban singkat
OCaml adalah bahasa fungsional bertipe statis dari keluarga ML. Compiler-nya menyimpulkan tipe untuk Anda, menangkap banyak kesalahan sebelum program berjalan, dan menghasilkan kode native yang cepat. Program disusun dari nilai immutable, variant (tagged union), pattern matching, dan modul. Pasang dengan opam, jalankan file dengan ocaml hello.ml, atau kompilasi dengan ocamlopt.
Apa itu OCaml dan siapa yang memakainya
OCaml dibuat di Inria, Prancis, dan kini dikembangkan oleh komunitas open source yang mencakup perusahaan seperti Jane Street dan Tarides. OCaml menggabungkan pemrograman fungsional dengan fitur imperatif opsional (mutable reference, array, perulangan) dan sistem objek yang tidak dibutuhkan sebagian besar kode. OCaml 5 menambahkan paralelisme shared-memory lewat domain dan effect handler.
OCaml dipakai untuk compiler dan tool analisis program, proof assistant seperti Rocq (dahulu Coq), sistem trading (Jane Street adalah pengguna industri yang paling dikenal), dan tool developer seperti Flow dan Infer dari Meta. OCaml juga bahasa pengajaran yang umum untuk pemrograman fungsional dan sistem tipe.
Memasang OCaml dan menjalankan Hello, world
Cara standar memasang OCaml adalah opam, package manager OCaml. Setelah opam terpasang, jalankan opam init satu kali; perintah ini menyiapkan compiler. Lalu pasang build tool dune dan REPL yang lebih ramah, utop, dengan opam install dune utop.
(* hello.ml *)
let () = print_endline "Hello, world!"ocaml hello.ml # run with the interpreter
ocamlopt -o hello hello.ml
./hello # native executable
# Hello, world!let () = ... adalah cara lazim menulis entry point: ekspresi dievaluasi dan diperiksa bahwa hasilnya unit (tanpa nilai). Di REPL (utop atau ocaml), akhiri setiap frasa dengan ;;; di file source Anda tidak memerlukan ;;. Untuk proyek nyata, dune init project myapp membuat proyek dan dune build mengompilasinya.
Nilai dan tipe dasar
| Tipe | Contoh | Catatan |
|---|---|---|
| int | 42 | 63-bit pada sistem 64-bit; operator + - * / mod |
| float | 3.14 | Punya operator sendiri: +. -. *. /. |
| string | "hello" | Byte immutable; digabung dengan ^ |
| char | 'a' | Satu byte |
| bool | true, false | &&, ||, not |
| unit | () | Nilai dari ekspresi yang tidak menghasilkan apa pun |
let name = "Ana"
let age = 30
let height = 1.68 *. 100.0
let () = Printf.printf "%s is %d, %.0f cm\n" name age height
(* Ana is 30, 168 cm *)
let count = ref 0
let () = incr count; Printf.printf "count = %d\n" !countBinding bersifat immutable. ref adalah sel yang bisa diubah: !r membacanya dan r := v menulisnya. OCaml tidak pernah mengonversi int dan float secara otomatis; gunakan float_of_int dan int_of_float.
Alur kontrol dan fungsi
if adalah ekspresi. Fungsi didefinisikan dengan let; fungsi rekursif memerlukan let rec. Argumen dipisahkan spasi, dan setiap fungsi di-curry, sehingga partial application gratis.
let sign n =
if n > 0 then "positive"
else if n < 0 then "negative"
else "zero"
let rec factorial n = if n <= 1 then 1 else n * factorial (n - 1)
let add x y = x + y (* int -> int -> int *)
let add5 = add 5
let () =
for i = 1 to 3 do
Printf.printf "%d squared is %d\n" i (i * i)
done;
Printf.printf "%s %d %d\n" (sign (-2)) (factorial 5) (add5 10)
(* negative 120 15 *)Perhatikan tanda kurung pada sign (-2): tanpa itu OCaml membaca sign - 2 sebagai pengurangan. Gunakan ; untuk merangkai ekspresi yang mengembalikan unit.
List, array, tuple, dan record
| Struktur | Literal | Catatan |
|---|---|---|
| List | [1; 2; 3] | Singly linked list immutable; x :: xs menambahkan di depan |
| Array | [| 1; 2; 3 |] | Ukuran tetap, mutable, pengindeksan a.(0) |
| Tuple | ("Ana", 30) | Kelompok nilai tetap dengan tipe berbeda |
| Record | { name = "Ana"; age = 30 } | Field bernama, tipe dideklarasikan lebih dulu |
| Hashtbl / Map | Hashtbl.create 16 | Hash table mutable / map berupa pohon seimbang yang immutable |
type person = { name : string; age : int }
let people = [ { name = "Ana"; age = 30 }; { name = "Ben"; age = 17 } ]
let () =
people
|> List.filter (fun p -> p.age >= 18)
|> List.map (fun p -> p.name)
|> List.iter print_endline
(* Ana *)
let older = { (List.hd people) with age = 31 }Operator pipeline x |> f berarti f x. Modul List menyediakan map, filter, fold_left, find_opt, dan banyak lagi.
Fitur khas: variant, pattern matching, dan modul
Tipe variant mendaftar setiap kemungkinan case dari sebuah nilai. Pattern matching membongkar nilai berdasarkan case, dan compiler memberi peringatan bila ada case yang terlewat, sehingga refactoring menjadi aman.
type shape =
| Circle of float
| Rectangle of float * float
let area = function
| Circle r -> Float.pi *. r *. r
| Rectangle (w, h) -> w *. h
let () =
List.iter (fun s -> Printf.printf "%.2f\n" (area s))
[ Circle 1.0; Rectangle (2.0, 3.0) ]
(* 3.14 then 6.00 *)
module StringMap = Map.Make (String)
let ages = StringMap.(empty |> add "Ana" 30 |> add "Ben" 17)
let () = Printf.printf "%d\n" (StringMap.find "Ana" ages) (* 30 *)Modul mengelompokkan tipe dan fungsi, dan setiap file adalah modul (list.ml menjadi List). Functor adalah fungsi dari modul ke modul: Map.Make (String) membangun modul map yang key-nya string. Signature (file .mli) menyembunyikan detail implementasi.
Penanganan error
OCaml punya tiga alat: option untuk nilai yang mungkin tidak ada, result untuk operasi yang bisa gagal beserta informasinya, dan exception untuk situasi luar biasa.
let parse_age s =
match int_of_string_opt s with
| Some n when n >= 0 -> Ok n
| Some _ -> Error "Age must not be negative"
| None -> Error "Not a number"
let () =
match parse_age "abc" with
| Ok n -> Printf.printf "Age %d\n" n
| Error msg -> print_endline ("Error: " ^ msg)
(* Error: Not a number *)
exception Empty_input
let first = function [] -> raise Empty_input | x :: _ -> x
let () =
try print_int (first []) with Empty_input -> print_endline "empty list"Program lengkap kecil: frekuensi kata
let () =
let text = "the cat and the hat and the bat" in
let counts = Hashtbl.create 16 in
String.split_on_char ' ' text
|> List.iter (fun w ->
let n = Option.value (Hashtbl.find_opt counts w) ~default:0 in
Hashtbl.replace counts w (n + 1));
Hashtbl.to_seq counts
|> List.of_seq
|> List.sort (fun (_, a) (_, b) -> compare b a)
|> List.filteri (fun i _ -> i < 2)
|> List.iter (fun (w, n) -> Printf.printf "%s %d\n" w n)
(* the 3
and 2 *)Program ini menghitung kata dalam hash table mutable, mengubah tabel menjadi list pasangan (word, count), mengurutkan berdasarkan jumlah secara menurun, dan mencetak dua yang pertama. ~default:0 adalah labeled argument.
Langkah selanjutnya
- ocaml.org: panduan instalasi, "A Tour of OCaml", dan tutorial lain di bawah Docs.
- Manual OCaml untuk referensi lengkap bahasa dan standard library.
- Pelajari dune untuk membangun proyek dan opam untuk memasang library.
- Coba buku online gratis "Real World OCaml" untuk contoh praktis yang lebih besar.
FAQ
Apakah OCaml sulit dipelajari?
Sintaksnya kecil, tetapi berpikir dengan tipe, rekursi, dan pattern matching butuh latihan jika Anda berasal dari bahasa imperatif. Pesan error dari type checker cepat menjadi lebih mudah dibaca.
Mengapa OCaml punya operator terpisah untuk float?
OCaml tidak melakukan overload pada operator aritmetika, jadi + hanya bekerja pada int dan +. hanya pada float. Ini menjaga inferensi tipe tetap sederhana dan dapat diprediksi.
Apa perbedaan OCaml dan F#?
F# diturunkan dari OCaml dan berbagi banyak sintaks intinya, tetapi F# berjalan di .NET dan memakai indentasi bermakna, sedangkan OCaml dikompilasi ke kode native atau bytecode dan punya sistem modul yang lebih kuat dengan functor.
Kapan saya memerlukan ;; di OCaml?
Hanya di toplevel interaktif (ocaml atau utop), tempat tanda ini memberi tahu REPL untuk mengevaluasi yang Anda ketik. Di file source .ml biasanya dihilangkan.