2014-09-10 17:17:03 +04:00
- - -
2014-09-10 19:35:30 +04:00
language : OCaml
2017-08-25 11:07:26 +03:00
filename : learnocaml . ml
2014-09-10 17:17:03 +04:00
contributors :
- [ " Daniil Baturin " , " http://baturin.org/ " ]
2023-06-30 15:00:21 +03:00
- [ " Stanislav Modrak " , " https://stanislav.gq/ " ]
2023-12-31 15:09:15 +03:00
- [ " Luke Tong " , " https://lukert.me/ " ]
2014-09-10 17:17:03 +04:00
- - -
OCaml is a strictly evaluated functional language with some imperative
features .
2023-07-20 01:47:11 +03:00
Along with Standard ML and its dialects it belongs to ML language family .
2014-09-12 15:39:15 +04:00
F # is also heavily influenced by OCaml .
2023-07-20 01:47:11 +03:00
Just like Standard ML , OCaml features both an interpreter , that can be
2014-09-12 16:46:41 +04:00
used interactively , and a compiler .
2023-07-20 01:47:11 +03:00
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 .
2014-09-10 17:17:03 +04:00
2023-12-31 15:09:15 +03:00
It also includes a package manager , ` opam ` , and a build system , ` dune ` .
2014-09-10 17:17:03 +04:00
It is strongly and statically typed , but instead of using manually written
2023-07-20 01:47:11 +03:00
type annotations , it infers types of expressions using the
[ Hindley - Milner ] ( https : // en . wikipedia . org / wiki / Hindley % E2 % 80 % 93Milner_type_system )
algorithm .
2014-09-10 17:17:03 +04:00
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
2023-07-20 01:47:11 +03:00
after you enter an expression
2014-09-10 19:35:30 +04:00
2014-09-10 17:17:03 +04:00
` ` `
# let inc x = x + 1 ;;
val inc : int -> int = < fun >
# let a = 99 ;;
val a : int = 99
` ` `
2023-07-20 01:47:11 +03:00
For a source file you can use the ` ocamlc - i / path / to / file . ml ` command
to print all names and type signatures
2014-09-10 17:17:03 +04:00
` ` `
2015-10-08 06:11:24 +03:00
$ cat sigtest . ml
2014-09-10 17:17:03 +04:00
let inc x = x + 1
let add x y = x + y
2015-10-08 06:11:24 +03:00
let a = 1
2014-09-10 17:17:03 +04:00
2015-10-08 06:11:24 +03:00
$ ocamlc - i . / sigtest . ml
2014-09-10 17:17:03 +04:00
val inc : int -> int
val add : int -> int -> int
val a : int
` ` `
2014-09-10 19:35:30 +04:00
2014-09-10 17:17:03 +04:00
Note that type signatures of functions of multiple arguments are
2023-07-20 01:47:11 +03:00
written in [ curried ] ( https : // en . wikipedia . org / wiki / Currying ) form .
A function that takes multiple arguments can be
2014-09-12 16:34:50 +04:00
represented as a composition of functions that take only one argument .
2023-07-20 01:47:11 +03:00
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 .
2014-09-12 16:34:50 +04:00
2014-09-10 17:17:03 +04:00
` ` ` ocaml
2014-09-10 18:33:41 +04:00
(* * * Comments * * *)
2014-09-10 17:17:03 +04:00
(* Comments are enclosed in (* and *) . It's fine to nest comments. *)
2014-09-10 18:33:41 +04:00
(* There are no single-line comments. *)
2014-09-10 17:17:03 +04:00
2014-09-10 18:33:41 +04:00
(* * * Variables and functions * * *)
2014-09-10 17:17:03 +04:00
2023-07-20 01:47:11 +03:00
(* Expressions can be separated by a double semicolon ";;".
2014-09-10 17:17:03 +04:00
In many cases it's redundant , but in this tutorial we use it after
2014-09-11 18:40:15 +04:00
every expression for easy pasting into the interpreter shell .
Unnecessary use of expression separators in source code files
is often considered to be a bad style . * )
2014-09-10 17:17:03 +04:00
2023-07-20 01:47:11 +03:00
(* Variable and function declarations use the "let" keyword. *)
2023-12-31 15:09:15 +03:00
(* Variables are immutable by default in OCaml *)
2014-09-10 17:17:03 +04:00
let x = 10 ;;
2014-09-11 18:40:15 +04:00
(* OCaml allows single quote characters in identifiers.
Single quote doesn't have a special meaning in this case , it's often used
in cases when in other languages one would use names like " foo_tmp " . * )
let foo = 1 ;;
let foo' = foo * 2 ;;
2014-09-10 18:33:41 +04:00
(* Since OCaml compiler infers types automatically, you normally don't need to
2014-09-12 16:42:50 +04:00
specify argument types explicitly . However , you can do it if
you want or need to . * )
2014-09-12 21:46:46 +04:00
let inc_int ( x : int ) : int = x + 1 ;;
(* One of the cases when explicit type annotations may be needed is
resolving ambiguity between two record types that have fields with
the same name . The alternative is to encapsulate those types in
modules , but both topics are a bit out of scope of this
tutorial . * )
2014-09-10 17:17:03 +04:00
(* You need to mark recursive function definitions as such with "rec" keyword. *)
let rec factorial n =
if n = 0 then 1
2014-10-18 07:44:44 +04:00
else n * factorial ( n - 1 )
2014-09-10 17:17:03 +04:00
;;
2014-09-10 18:33:41 +04:00
(* Function application usually doesn't need parentheses around arguments *)
2014-09-10 17:17:03 +04:00
let fact_5 = factorial 5 ;;
2014-09-10 18:33:41 +04:00
(* ...unless the argument is an expression. *)
2014-09-10 17:17:03 +04:00
let fact_4 = factorial ( 5 - 1 ) ;;
let sqr2 = sqr ( - 2 ) ;;
(* Every function must have at least one argument.
2016-02-27 01:43:41 +03:00
Since some functions naturally don't take any arguments , there's
2014-09-10 17:17:03 +04:00
" unit " type for it that has the only one value written as " () " * )
let print_hello () = print_endline " hello world " ;;
2023-07-20 01:47:11 +03:00
(* Note that you must specify " ( ) " as the argument when calling it. *)
2014-09-10 17:17:03 +04:00
print_hello () ;;
2023-07-20 01:47:11 +03:00
(* Calling a function with an insufficient number of arguments
2014-09-10 17:17:03 +04:00
does not cause an error , it produces a new function . * )
let make_inc x y = x + y ;; (* make_inc is int -> int -> int *)
let inc_2 = make_inc 2 ;; (* inc_2 is int -> int *)
inc_2 3 ;; (* Evaluates to 5 *)
2023-07-20 01:47:11 +03:00
(* You can use multiple expressions in the function body.
2014-09-10 18:33:41 +04:00
The last expression becomes the return value . All other
expressions must be of the " unit " type .
This is useful when writing in imperative style , the simplest
2023-07-20 01:47:11 +03:00
form of which is inserting a debug print . * )
2014-09-10 18:33:41 +04:00
let print_and_return x =
print_endline ( string_of_int x ) ;
x
;;
2014-09-10 17:17:03 +04:00
(* Since OCaml is a functional language, it lacks "procedures".
2023-07-20 01:47:11 +03:00
Every function must return something . So functions that do not
really return anything and are called solely for their side
effects , like print_endline , return a value of " unit " type . * )
2014-09-10 17:17:03 +04:00
2023-07-20 01:47:11 +03:00
(* Definitions can be chained with the "let ... in" construct.
This is roughly the same as assigning values to multiple
2014-09-10 17:17:03 +04:00
variables before using them in expressions in imperative
languages . * )
let x = 10 in
let y = 20 in
x + y ;;
2023-07-20 01:47:11 +03:00
(* Alternatively you can use the "let ... and ... in" construct.
2014-09-10 17:17:03 +04:00
This is especially useful for mutually recursive functions ,
2023-07-20 01:47:11 +03:00
with ordinary " let ... in " the compiler will complain about
2015-02-12 11:54:26 +03:00
unbound values . * )
let rec
is_even = function
| 0 -> true
| n -> is_odd ( n - 1 )
and
is_odd = function
| 0 -> false
| n -> is_even ( n - 1 )
;;
2014-09-10 17:17:03 +04:00
2014-09-12 21:54:23 +04:00
(* Anonymous functions use the following syntax: *)
let my_lambda = fun x -> x * x ;;
2014-09-10 17:17:03 +04:00
2014-09-10 18:33:41 +04:00
(* * * Operators * * *)
2014-09-10 17:17:03 +04:00
2019-01-10 04:06:14 +03:00
(* There is little distinction between operators and functions.
2014-09-10 17:17:03 +04:00
Every operator can be called as a function . * )
( + ) 3 4 (* Same as 3 + 4 *)
2014-09-10 18:33:41 +04:00
(* There's a number of built-in operators. One unusual feature is
2014-09-10 17:17:03 +04:00
that OCaml doesn't just refrain from any implicit conversions
between integers and floats , it also uses different operators
for floats . * )
2014-09-10 18:33:41 +04:00
12 + 3 ;; (* Integer addition. *)
12 . 0 + . 3 . 0 ;; (* Floating point addition. *)
2014-09-10 17:17:03 +04:00
2014-09-10 18:33:41 +04:00
12 / 3 ;; (* Integer division. *)
12 . 0 /. 3 . 0 ;; (* Floating point division. *)
5 mod 2 ;; (* Remainder. *)
2014-09-10 17:17:03 +04:00
(* Unary minus is a notable exception, it's polymorphic.
However , it also has " pure " integer and float forms . * )
- 3 ;; (* Polymorphic, integer *)
2014-09-10 18:33:41 +04:00
- 4 . 5 ;; (* Polymorphic, float *)
2014-09-10 17:17:03 +04:00
~ - 3 (* Integer only *)
~ - 3 . 4 (* Type error *)
~ -. 3 . 4 (* Float only *)
(* You can define your own operators or redefine existing ones.
2023-07-20 01:47:11 +03:00
Unlike Standard ML or Haskell , only certain symbols can be
used for operator names and the operator's first symbol determines
its associativity and precedence rules . * )
2014-09-10 18:33:41 +04:00
let ( + ) a b = a - b ;; (* Surprise maintenance programmers. *)
2014-09-10 17:17:03 +04:00
(* More useful: a reciprocal operator for floats.
2014-09-10 18:33:41 +04:00
Unary operators must start with " ~ " . * )
2014-09-10 17:17:03 +04:00
let ( ~ / ) x = 1 . 0 /. x ;;
~ / 4 . 0 (* = 0.25 *)
2015-10-17 15:06:28 +03:00
(* * * Built-in data structures * * *)
2014-09-10 17:17:03 +04:00
(* Lists are enclosed in square brackets, items are separated by
semicolons . * )
2022-01-03 19:18:53 +03:00
let my_list = [ 1 ; 2 ; 3 ] ;; (* Has type "int list". *)
2014-09-10 17:17:03 +04:00
2014-09-10 18:33:41 +04:00
(* Tuples are ( optionally ) enclosed in parentheses, items are separated
by commas . * )
let first_tuple = 3 , 4 ;; (* Has type "int * int". *)
2014-09-10 17:17:03 +04:00
let second_tuple = ( 4 , 5 ) ;;
(* Corollary: if you try to separate list items by commas, you get a list
with a tuple inside , probably not what you want . * )
let bad_list = [ 1 , 2 ] ;; (* Becomes [ ( 1, 2 ) ] *)
2014-09-10 18:33:41 +04:00
(* You can access individual list items with the List.nth function. *)
2014-09-10 17:17:03 +04:00
List . nth my_list 1 ;;
2014-09-12 21:54:23 +04:00
(* There are higher-order functions for lists such as map and filter. *)
List . map ( fun x -> x * 2 ) [ 1 ; 2 ; 3 ] ;;
2016-03-26 15:27:56 +03:00
List . filter ( fun x -> x mod 2 = 0 ) [ 1 ; 2 ; 3 ; 4 ] ;;
2014-09-12 21:54:23 +04:00
2014-09-10 18:33:41 +04:00
(* You can add an item to the beginning of a list with the "::" constructor
2014-09-10 17:17:03 +04:00
often referred to as " cons " . * )
1 :: [ 2 ; 3 ] ;; (* Gives [1; 2; 3] *)
2023-12-31 15:09:15 +03:00
(* Remember that the cons :: constructor can only cons a single item to the front
of a list . To combine two lists use the append @ operator * )
[ 1 ; 2 ] @ [ 3 ; 4 ] ;; (* Gives [1; 2; 3; 4] *)
2014-09-10 17:17:03 +04:00
(* Arrays are enclosed in [| |] *)
let my_array = [| 1 ; 2 ; 3 |] ;;
(* You can access array items like this: *)
my_array . ( 0 ) ;;
2014-09-11 18:22:02 +04:00
(* * * Strings and characters * * *)
(* Use double quotes for string literals. *)
let my_str = " Hello world " ;;
(* Use single quotes for character literals. *)
let my_char = 'a' ;;
(* Single and double quotes are not interchangeable. *)
let bad_str = ' syntax error' ;; (* Syntax error. *)
(* This will give you a single character string, not a character. *)
let single_char_str = " w " ;;
(* Strings can be concatenated with the "^" operator. *)
let some_str = " hello " ^ " world " ;;
(* Strings are not arrays of characters.
You can't mix characters and strings in expressions .
You can convert a character to a string with " String.make 1 my_char " .
There are more convenient functions for this purpose in additional
libraries such as Core . Std that may not be installed and / or loaded
by default . * )
let ocaml = ( String . make 1 'O' ) ^ " Caml " ;;
(* There is a printf function. *)
Printf . printf " %d %s " 99 " bottles of beer " ;;
2023-07-20 01:47:11 +03:00
(* There's also unformatted read and write functions. *)
2014-09-11 18:22:02 +04:00
print_string " hello world \n " ;;
print_endline " hello world " ;;
let line = read_line () ;;
2014-09-10 17:17:03 +04:00
2014-09-10 18:33:41 +04:00
(* * * User-defined data types * * *)
2014-09-10 17:17:03 +04:00
2014-09-10 18:33:41 +04:00
(* You can define types with the "type some_type =" construct. Like in this
2014-09-10 17:17:03 +04:00
useless type alias : * )
type my_int = int ;;
(* More interesting types include so called type constructors.
Constructors must start with a capital letter . * )
type ml = OCaml | StandardML ;;
2014-09-10 18:33:41 +04:00
let lang = OCaml ;; (* Has type "ml". *)
2014-09-10 17:17:03 +04:00
(* Type constructors don't need to be empty. *)
type my_number = PlusInfinity | MinusInfinity | Real of float ;;
2014-09-10 18:33:41 +04:00
let r0 = Real ( - 3 . 4 ) ;; (* Has type "my_number". *)
2014-09-10 17:17:03 +04:00
(* Can be used to implement polymorphic arithmetics. *)
type number = Int of int | Float of float ;;
(* Point on a plane, essentially a type-constrained tuple *)
type point2d = Point of float * float ;;
let my_point = Point ( 2 . 0 , 3 . 0 ) ;;
2014-09-10 18:40:47 +04:00
(* Types can be parameterized, like in this type for "list of lists
2014-09-10 17:17:03 +04:00
of anything " . 'a can be substituted with any type. *)
type ' a list_of_lists = ' a list list ;;
type int_list_list = int list_of_lists ;;
2023-12-31 15:09:15 +03:00
(* These features allow for useful optional types *)
type ' a option = Some of ' a | None ;;
let x = Some x ;;
let y = None ;;
2014-09-10 18:33:41 +04:00
(* Types can also be recursive. Like in this type analogous to
2023-07-20 01:47:11 +03:00
a built - in list of integers . * )
2014-09-10 17:17:03 +04:00
type my_int_list = EmptyList | IntList of int * my_int_list ;;
2015-02-12 12:02:16 +03:00
let l = IntList ( 1 , EmptyList ) ;;
2014-09-10 17:17:03 +04:00
2023-12-31 15:09:15 +03:00
(* or Trees *)
type ' a tree =
| Empty
| Node of ' a tree * ' a * ' a tree
let example_tree : int tree =
Node (
Node ( Empty , 7 , Empty ) ,
5 ,
Node ( Empty , 9 , Empty )
)
(*
5
/ \
7 9
* )
(* * * Records * * *)
(* A collection of values with named fields *)
type animal =
{
name : string ;
color : string ;
legs : int ;
}
;;
let cow =
{ name : " cow " ;
color : " black and white " ;
legs : 4 ;
}
;;
val cow : animal
cow . name ;;
- : string = " cow "
2014-09-10 17:17:03 +04:00
2014-09-10 18:33:41 +04:00
(* * * Pattern matching * * *)
2014-09-10 17:17:03 +04:00
2023-07-20 01:47:11 +03:00
(* Pattern matching is somewhat similar to the switch statement in imperative
2014-09-10 17:17:03 +04:00
languages , but offers a lot more expressive power .
2015-10-08 06:11:24 +03:00
Even though it may look complicated , it really boils down to matching
2014-09-12 16:42:50 +04:00
an argument against an exact value , a predicate , or a type constructor .
The type system is what makes it so powerful . * )
2014-09-10 17:17:03 +04:00
2014-09-10 18:33:41 +04:00
(* * Matching exact values. * *)
2014-09-10 17:17:03 +04:00
let is_zero x =
match x with
| 0 -> true
2023-07-20 01:47:11 +03:00
| _ -> false (* The "_" means "anything else". *)
2014-09-10 17:17:03 +04:00
;;
2014-09-10 18:33:41 +04:00
(* Alternatively, you can use the "function" keyword. *)
2014-09-12 16:35:56 +04:00
let is_one = function
2014-09-10 17:17:03 +04:00
| 1 -> true
| _ -> false
;;
2014-09-10 18:33:41 +04:00
(* Matching predicates, aka "guarded pattern matching". *)
2015-10-08 06:11:24 +03:00
let abs x =
2014-09-10 17:17:03 +04:00
match x with
| x when x < 0 -> - x
| _ -> x
;;
abs 5 ;; (* 5 *)
abs ( - 5 ) (* 5 again *)
2014-09-10 18:33:41 +04:00
(* * Matching type constructors * *)
2014-09-10 17:17:03 +04:00
type animal = Dog of string | Cat of string ;;
let say x =
match x with
| Dog x -> x ^ " says woof "
| Cat x -> x ^ " says meow "
;;
2014-09-10 18:33:41 +04:00
say ( Cat " Fluffy " ) ;; (* "Fluffy says meow". *)
2014-09-10 17:17:03 +04:00
2023-12-31 15:09:15 +03:00
(* However, pattern matching must be exhaustive *)
type color = Red | Blue | Green ;;
let what_color x =
match x with
| Red -> " color is red "
| Blue -> " color is blue "
(* Won't compile! You have to add a _ case or a Green case
to ensure all possibilities are accounted for * )
;;
(* Also, the match statement checks each case in order.
So , if a _ case appears first , none of the
following cases will be reached ! * )
2015-10-17 15:06:28 +03:00
(* * Traversing data structures with pattern matching * *)
2014-09-10 17:17:03 +04:00
(* Recursive types can be traversed with pattern matching easily.
2015-10-17 15:06:28 +03:00
Let's see how we can traverse a data structure of the built - in list type .
2014-09-12 16:42:50 +04:00
Even though the built - in cons ( " :: " ) looks like an infix operator ,
it's actually a type constructor and can be matched like any other . * )
2014-09-10 17:17:03 +04:00
let rec sum_list l =
match l with
| [] -> 0
| head :: tail -> head + ( sum_list tail )
;;
2014-09-10 18:33:41 +04:00
sum_list [ 1 ; 2 ; 3 ] ;; (* Evaluates to 6 *)
2014-09-10 17:17:03 +04:00
2014-09-10 18:33:41 +04:00
(* Built-in syntax for cons obscures the structure a bit, so we'll make
2014-09-10 17:17:03 +04:00
our own list for demonstration . * )
type int_list = Nil | Cons of int * int_list ;;
let rec sum_int_list l =
match l with
| Nil -> 0
| Cons ( head , tail ) -> head + ( sum_int_list tail )
;;
let t = Cons ( 1 , Cons ( 2 , Cons ( 3 , Nil ) ) ) ;;
sum_int_list t ;;
2023-12-31 15:09:15 +03:00
(* Heres a function to tell if a list is sorted *)
let rec is_sorted l =
match l with
| x :: y :: tail -> x < = y && is_sorted ( y :: tail )
| _ -> true
;;
is_sorted [ 1 ; 2 ; 3 ] ;; (* True *)
(* OCaml's powerful type inference guesses that l is of type int list
since the < = operator is used on elements of l * )
(* And another to reverse a list *)
let rec rev ( l : ' a list ) : ' a list =
match l with
| [] -> []
| x :: tl -> ( rev tl ) @ [ x ]
;;
rev [ 1 ; 2 ; 3 ] ;; (* Gives [3; 2; 1] *)
(* This function works on lists of any element type *)
(* * * Higher Order Functions * * *)
(* Functions are first class in OCaml *)
let rec transform ( f : ' a -> ' b ) ( l : ' a list ) : ' b list =
match l with
| [] -> []
| head :: tail -> ( f head ) :: transform f tail
;;
transform ( fun x -> x + 1 ) [ 1 ; 2 ; 3 ] ;; (* Gives [2; 3; 4] *)
(* * Lets combine everything we learned! * *)
let rec filter ( pred : ' a -> bool ) ( l : ' a list ) : ' a list =
begin match l with
| [] -> []
| x :: xs ->
let rest = filter pred xs in
if pred x then x :: rest else rest
end
;;
filter ( fun x -> x < 4 ) [ 3 ; 1 ; 4 ; 1 ; 5 ] ;; (* Gives [3; 1; 1] ) *)
(* * * Mutability * * *)
(* Records and variables are immutable: you cannot change where a variable points to *)
(* However, you can create mutable polymorphic fields *)
type counter = { mutable num : int } ;;
let c = { num : 0 } ;;
c . num ;; (* Gives 0 *)
c . num <- 1 ;; (* <- operator can set mutable record fields *)
c . num ;; (* Gives 1 *)
(* OCaml's standard library provides a ref type to make single field mutability easier *)
type ' a ref = { mutable contents : ' a } ;;
let counter = ref 0 ;;
! counter ;; (* ! operator returns x.contents *)
counter := ! counter + 1 ;; (* := can be used to set contents *)
2014-09-10 17:17:03 +04:00
` ` `
# # Further reading
2023-12-31 15:09:15 +03:00
* Visit the official website to get the compiler and read the docs : [ http : // ocaml . org / ] ( http : // ocaml . org / )
* Quick tutorial on OCaml : [ https : // ocaml . org / docs / up - and - running ] ( https : // ocaml . org / docs / up - and - running )
* Complete online OCaml v5 playground : [ https : // ocaml . org / play ] ( https : // ocaml . org / play )
* An up - to - date ( 2022 ) book ( with free online version ) " Real World OCaml " : [ https : // www . cambridge . org / core / books / real - world - ocaml - functional - programming - for - the - masses / 052E4BCCB09D56A0FE875DD81B1ED571 ] ( https : // www . cambridge . org / core / books / real - world - ocaml - functional - programming - for - the - masses / 052E4BCCB09D56A0FE875DD81B1ED571 )
* Online interactive textbook " OCaml Programming: Correct + Efficient + Beautiful " from Cornell University : [ https : // cs3110 . github . io / textbook / cover . html ] ( https : // cs3110 . github . io / textbook / cover . html )
* Try interactive tutorials and a web - based interpreter by OCaml Pro : [ http : // try . ocamlpro . com / ] ( http : // try . ocamlpro . com / )