cv.cm

Pemrograman · Bahasa pemrograman

Tutorial OCaml untuk pemula

6 menit baca

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

TipeContohCatatan
int4263-bit pada sistem 64-bit; operator + - * / mod
float3.14Punya operator sendiri: +. -. *. /.
string"hello"Byte immutable; digabung dengan ^
char'a'Satu byte
booltrue, 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" !count

Binding 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

StrukturLiteralCatatan
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 / MapHashtbl.create 16Hash 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.

Semua tutorial pemrograman