OCaml

Личный сайт Go-разработчика из Казани

OCaml is a strictly evaluated functional language with some imperative features.

Along with Standard ML and its dialects it belongs to ML language family. F# is also heavily influenced by OCaml.

Just like Standard ML, OCaml features both an interpreter, that can be used interactively, and a compiler. The interpreter binary is normally called ocaml and the compiler is ocamlopt. There is also a bytecode compiler, ocamlc, but there are few reasons to use it.

It also includes a package manager, opam, and a build system, dune.

It is strongly and statically typed, but instead of using manually written type annotations, it infers types of expressions using the Hindley-Milner algorithm. It makes type annotations unnecessary in most cases, but can be a major source of confusion for beginners.

When you are in the top level loop, OCaml will print the inferred type after you enter an expression

# let inc x = x	+ 1 ;;
val inc : int -> int = <fun>
# let a = 99 ;;
val a : int = 99

For a source file you can use the ocamlc -i /path/to/file.ml command to print all names and type signatures

$ cat sigtest.ml
let inc x = x + 1
let add x y = x + y

let a = 1

$ ocamlc -i ./sigtest.ml
val inc : int -> int
val add : int -> int -> int
val a : int

Note that type signatures of functions of multiple arguments are written in curried form. A function that takes multiple arguments can be represented as a composition of functions that take only one argument. The f(x,y) = x + y function from the example above applied to arguments 2 and 3 is equivalent to the f0(y) = 2 + y function applied to 3. Hence the int -> int -> int signature.

1(*** Comments ***) 2 3(* Comments are enclosed in (* and *). It's fine to nest comments. *) 4 5(* There are no single-line comments. *) 6 7 8(*** Variables and functions ***) 9 10(* Expressions can be separated by a double semicolon ";;". 11 In many cases it's redundant, but in this tutorial we use it after 12 every expression for easy pasting into the interpreter shell. 13 Unnecessary use of expression separators in source code files 14 is often considered to be a bad style. *) 15 16(* Variable and function declarations use the "let" keyword. *) 17(* Variables are immutable by default in OCaml *) 18let x = 10 ;; 19 20(* OCaml allows single quote characters in identifiers. 21 Single quote doesn't have a special meaning in this case, it's often used 22 in cases when in other languages one would use names like "foo_tmp". *) 23let foo = 1 ;; 24let foo' = foo * 2 ;; 25 26(* Since OCaml compiler infers types automatically, you normally don't need to 27 specify argument types explicitly. However, you can do it if 28 you want or need to. *) 29let inc_int (x: int) : int = x + 1 ;; 30 31(* One of the cases when explicit type annotations may be needed is 32 resolving ambiguity between two record types that have fields with 33 the same name. The alternative is to encapsulate those types in 34 modules, but both topics are a bit out of scope of this 35 tutorial. *) 36 37(* You need to mark recursive function definitions as such with "rec" keyword. *) 38let rec factorial n = 39 if n = 0 then 1 40 else n * factorial (n-1) 41;; 42 43(* Function application usually doesn't need parentheses around arguments *) 44let fact_5 = factorial 5 ;; 45 46(* ...unless the argument is an expression. *) 47let fact_4 = factorial (5-1) ;; 48let sqr2 = sqr (-2) ;; 49 50(* Every function must have at least one argument. 51 Since some functions naturally don't take any arguments, there's 52 "unit" type for it that has the only one value written as "()" *) 53let print_hello () = print_endline "hello world" ;; 54 55(* Note that you must specify "()" as the argument when calling it. *) 56print_hello () ;; 57 58(* Calling a function with an insufficient number of arguments 59 does not cause an error, it produces a new function. *) 60let make_inc x y = x + y ;; (* make_inc is int -> int -> int *) 61let inc_2 = make_inc 2 ;; (* inc_2 is int -> int *) 62inc_2 3 ;; (* Evaluates to 5 *) 63 64(* You can use multiple expressions in the function body. 65 The last expression becomes the return value. All other 66 expressions must be of the "unit" type. 67 This is useful when writing in imperative style, the simplest 68 form of which is inserting a debug print. *) 69let print_and_return x = 70 print_endline (string_of_int x); 71 x 72;; 73 74(* Since OCaml is a functional language, it lacks "procedures". 75 Every function must return something. So functions that do not 76 really return anything and are called solely for their side 77 effects, like print_endline, return a value of "unit" type. *) 78 79 80(* Definitions can be chained with the "let ... in" construct. 81 This is roughly the same as assigning values to multiple 82 variables before using them in expressions in imperative 83 languages. *) 84let x = 10 in 85let y = 20 in 86x + y ;; 87 88(* Alternatively you can use the "let ... and ... in" construct. 89 This is especially useful for mutually recursive functions, 90 with ordinary "let ... in" the compiler will complain about 91 unbound values. *) 92let rec 93 is_even = function 94 | 0 -> true 95 | n -> is_odd (n-1) 96and 97 is_odd = function 98 | 0 -> false 99 | n -> is_even (n-1) 100;; 101 102(* Anonymous functions use the following syntax: *) 103let my_lambda = fun x -> x * x ;; 104 105(*** Operators ***) 106 107(* There is little distinction between operators and functions. 108 Every operator can be called as a function. *) 109 110(+) 3 4 (* Same as 3 + 4 *) 111 112(* There's a number of built-in operators. One unusual feature is 113 that OCaml doesn't just refrain from any implicit conversions 114 between integers and floats, it also uses different operators 115 for floats. *) 11612 + 3 ;; (* Integer addition. *) 11712.0 +. 3.0 ;; (* Floating point addition. *) 118 11912 / 3 ;; (* Integer division. *) 12012.0 /. 3.0 ;; (* Floating point division. *) 1215 mod 2 ;; (* Remainder. *) 122 123(* Unary minus is a notable exception, it's polymorphic. 124 However, it also has "pure" integer and float forms. *) 125- 3 ;; (* Polymorphic, integer *) 126- 4.5 ;; (* Polymorphic, float *) 127~- 3 (* Integer only *) 128~- 3.4 (* Type error *) 129~-. 3.4 (* Float only *) 130 131(* You can define your own operators or redefine existing ones. 132 Unlike Standard ML or Haskell, only certain symbols can be 133 used for operator names and the operator's first symbol determines 134 its associativity and precedence rules. *) 135let (+) a b = a - b ;; (* Surprise maintenance programmers. *) 136 137(* More useful: a reciprocal operator for floats. 138 Unary operators must start with "~". *) 139let (~/) x = 1.0 /. x ;; 140~/4.0 (* = 0.25 *) 141 142 143(*** Built-in data structures ***) 144 145(* Lists are enclosed in square brackets, items are separated by 146 semicolons. *) 147let my_list = [1; 2; 3] ;; (* Has type "int list". *) 148 149(* Tuples are (optionally) enclosed in parentheses, items are separated 150 by commas. *) 151let first_tuple = 3, 4 ;; (* Has type "int * int". *) 152let second_tuple = (4, 5) ;; 153 154(* Corollary: if you try to separate list items by commas, you get a list 155 with a tuple inside, probably not what you want. *) 156let bad_list = [1, 2] ;; (* Becomes [(1, 2)] *) 157 158(* You can access individual list items with the List.nth function. *) 159List.nth my_list 1 ;; 160 161(* There are higher-order functions for lists such as map and filter. *) 162List.map (fun x -> x * 2) [1; 2; 3] ;; 163List.filter (fun x -> x mod 2 = 0) [1; 2; 3; 4] ;; 164 165(* You can add an item to the beginning of a list with the "::" constructor 166 often referred to as "cons". *) 1671 :: [2; 3] ;; (* Gives [1; 2; 3] *) 168 169(* Remember that the cons :: constructor can only cons a single item to the front 170 of a list. To combine two lists use the append @ operator *) 171[1; 2] @ [3; 4] ;; (* Gives [1; 2; 3; 4] *) 172 173(* Arrays are enclosed in [| |] *) 174let my_array = [| 1; 2; 3 |] ;; 175 176(* You can access array items like this: *) 177my_array.(0) ;; 178 179 180(*** Strings and characters ***) 181 182(* Use double quotes for string literals. *) 183let my_str = "Hello world" ;; 184 185(* Use single quotes for character literals. *) 186let my_char = 'a' ;; 187 188(* Single and double quotes are not interchangeable. *) 189let bad_str = 'syntax error' ;; (* Syntax error. *) 190 191(* This will give you a single character string, not a character. *) 192let single_char_str = "w" ;; 193 194(* Strings can be concatenated with the "^" operator. *) 195let some_str = "hello" ^ "world" ;; 196 197(* Strings are not arrays of characters. 198 You can't mix characters and strings in expressions. 199 You can convert a character to a string with "String.make 1 my_char". 200 There are more convenient functions for this purpose in additional 201 libraries such as Core.Std that may not be installed and/or loaded 202 by default. *) 203let ocaml = (String.make 1 'O') ^ "Caml" ;; 204 205(* There is a printf function. *) 206Printf.printf "%d %s" 99 "bottles of beer" ;; 207 208(* There's also unformatted read and write functions. *) 209print_string "hello world\n" ;; 210print_endline "hello world" ;; 211let line = read_line () ;; 212 213 214(*** User-defined data types ***) 215 216(* You can define types with the "type some_type =" construct. Like in this 217 useless type alias: *) 218type my_int = int ;; 219 220(* More interesting types include so called type constructors. 221 Constructors must start with a capital letter. *) 222type ml = OCaml | StandardML ;; 223let lang = OCaml ;; (* Has type "ml". *) 224 225(* Type constructors don't need to be empty. *) 226type my_number = PlusInfinity | MinusInfinity | Real of float ;; 227let r0 = Real (-3.4) ;; (* Has type "my_number". *) 228 229(* Can be used to implement polymorphic arithmetics. *) 230type number = Int of int | Float of float ;; 231 232(* Point on a plane, essentially a type-constrained tuple *) 233type point2d = Point of float * float ;; 234let my_point = Point (2.0, 3.0) ;; 235 236(* Types can be parameterized, like in this type for "list of lists 237 of anything". 'a can be substituted with any type. *) 238type 'a list_of_lists = 'a list list ;; 239type int_list_list = int list_of_lists ;; 240 241(* These features allow for useful optional types *) 242type 'a option = Some of 'a | None ;; 243let x = Some x ;; 244let y = None ;; 245 246(* Types can also be recursive. Like in this type analogous to 247 a built-in list of integers. *) 248type my_int_list = EmptyList | IntList of int * my_int_list ;; 249let l = IntList (1, EmptyList) ;; 250 251(* or Trees *) 252type 'a tree = 253 | Empty 254 | Node of 'a tree * 'a * 'a tree 255 256let example_tree: int tree = 257 Node ( 258 Node (Empty, 7, Empty), 259 5, 260 Node (Empty, 9, Empty) 261 ) 262(* 263 5 264 / \ 265 7 9 266*) 267 268(*** Records ***) 269 270(* A collection of values with named fields *) 271 272type animal = 273 { 274 name: string; 275 color: string; 276 legs: int; 277 } 278;; 279 280let cow = 281 { name = "cow"; 282 color = "black and white"; 283 legs = 4; 284 } 285;; 286val cow : animal 287 288cow.name ;; 289- : string = "cow" 290 291(*** Pattern matching ***) 292 293(* Pattern matching is somewhat similar to the switch statement in imperative 294 languages, but offers a lot more expressive power. 295 296 Even though it may look complicated, it really boils down to matching 297 an argument against an exact value, a predicate, or a type constructor. 298 The type system is what makes it so powerful. *) 299 300(** Matching exact values. **) 301 302let is_zero x = 303 match x with 304 | 0 -> true 305 | _ -> false (* The "_" means "anything else". *) 306;; 307 308(* Alternatively, you can use the "function" keyword. *) 309let is_one = function 310| 1 -> true 311| _ -> false 312;; 313 314(* Matching predicates, aka "guarded pattern matching". *) 315let abs x = 316 match x with 317 | x when x < 0 -> -x 318 | _ -> x 319;; 320 321abs 5 ;; (* 5 *) 322abs (-5) (* 5 again *) 323 324(** Matching type constructors **) 325 326type animal = Dog of string | Cat of string ;; 327 328let say x = 329 match x with 330 | Dog x -> x ^ " says woof" 331 | Cat x -> x ^ " says meow" 332;; 333 334say (Cat "Fluffy") ;; (* "Fluffy says meow". *) 335 336(* However, pattern matching must be exhaustive *) 337type color = Red | Blue | Green ;; 338let what_color x = 339 match x with 340 | Red -> "color is red" 341 | Blue -> "color is blue" 342 (* Won't compile! You have to add a _ case or a Green case 343 to ensure all possibilities are accounted for *) 344;; 345(* Also, the match statement checks each case in order. 346 So, if a _ case appears first, none of the 347 following cases will be reached! *) 348 349(** Traversing data structures with pattern matching **) 350 351(* Recursive types can be traversed with pattern matching easily. 352 Let's see how we can traverse a data structure of the built-in list type. 353 Even though the built-in cons ("::") looks like an infix operator, 354 it's actually a type constructor and can be matched like any other. *) 355let rec sum_list l = 356 match l with 357 | [] -> 0 358 | head :: tail -> head + (sum_list tail) 359;; 360 361sum_list [1; 2; 3] ;; (* Evaluates to 6 *) 362 363(* Built-in syntax for cons obscures the structure a bit, so we'll make 364 our own list for demonstration. *) 365 366type int_list = Nil | Cons of int * int_list ;; 367let rec sum_int_list l = 368 match l with 369 | Nil -> 0 370 | Cons (head, tail) -> head + (sum_int_list tail) 371;; 372 373let t = Cons (1, Cons (2, Cons (3, Nil))) ;; 374sum_int_list t ;; 375 376(* Heres a function to tell if a list is sorted *) 377let rec is_sorted l = 378 match l with 379 | x :: y :: tail -> x <= y && is_sorted (y :: tail) 380 | _ -> true 381;; 382 383is_sorted [1; 2; 3] ;; (* True *) 384(* OCaml's powerful type inference guesses that l is of type int list 385 since the <= operator is used on elements of l *) 386 387(* And another to reverse a list *) 388let rec rev (l: 'a list) : 'a list = 389 match l with 390 | [] -> [] 391 | x::tl -> (rev tl) @ [x] 392;; 393 394rev [1; 2; 3] ;; (* Gives [3; 2; 1] *) 395(* This function works on lists of any element type *) 396 397(*** Higher Order Functions ***) 398 399(* Functions are first class in OCaml *) 400 401let rec transform (f: 'a -> 'b) (l: 'a list) : 'b list = 402 match l with 403 | [] -> [] 404 | head :: tail -> (f head) :: transform f tail 405;; 406 407transform (fun x -> x + 1) [1; 2; 3] ;; (* Gives [2; 3; 4] *) 408 409(** Lets combine everything we learned! **) 410let rec filter (pred: 'a -> bool) (l: 'a list) : 'a list = 411 begin match l with 412 | [] -> [] 413 | x :: xs -> 414 let rest = filter pred xs in 415 if pred x then x :: rest else rest 416 end 417;; 418 419filter (fun x -> x < 4) [3; 1; 4; 1; 5] ;; (* Gives [3; 1; 1]) *) 420 421(*** Mutability ***) 422 423(* Records and variables are immutable: you cannot change where a variable points to *) 424 425(* However, you can create mutable polymorphic fields *) 426type counter = { mutable num : int } ;; 427 428let c = { num = 0 } ;; 429c.num ;; (* Gives 0 *) 430c.num <- 1 ;; (* <- operator can set mutable record fields *) 431c.num ;; (* Gives 1 *) 432 433(* OCaml's standard library provides a ref type to make single field mutability easier *) 434type 'a ref = { mutable contents : 'a } ;; 435let counter = ref 0 ;; 436!counter ;; (* ! operator returns x.contents *) 437counter := !counter + 1 ;; (* := can be used to set contents *)

Further reading