1
0
mirror of https://github.com/adambard/learnxinyminutes-docs.git synced 2025-08-06 14:56:54 +02:00

Fix some typos/errors in the OCaml tutorial.

This commit is contained in:
Daniil Baturin
2014-09-10 21:33:41 +07:00
parent 870289faa8
commit 9f3bff9ce8

View File

@@ -14,7 +14,7 @@ the compiler is "ocamlc.opt". There is also a bytecode compiler, "ocamlc",
but there are few reasons to use it. but there are few reasons to use it.
It is strongly and statically typed, but instead of using manually written It is strongly and statically typed, but instead of using manually written
type annotations it infers types of expressions using Hindley-Milner algorithm. type annotations, it infers types of expressions using Hindley-Milner algorithm.
It makes type annotations unnecessary in most cases, but can be a major It makes type annotations unnecessary in most cases, but can be a major
source of confusion for beginners. source of confusion for beginners.
@@ -46,24 +46,24 @@ Note that type signatures of functions of multiple arguments are
written in curried form. written in curried form.
```ocaml ```ocaml
(*** Comments ***)
(* Comments are enclosed in (* and *). It's fine to nest comments. *) (* Comments are enclosed in (* and *). It's fine to nest comments. *)
(* There are no single-line comments *) (* There are no single-line comments. *)
(** Variables and functions *) (*** Variables and functions ***)
(* Statements can be separated by double (* Expressions can be separated by a double semicolon symbol, ";;".
semicolon symbol, ";;".
In many cases it's redundant, but in this tutorial we use it after In many cases it's redundant, but in this tutorial we use it after
every expression for easy pasting into the interpreter shell. *) every expression for easy pasting into the interpreter shell. *)
(* Variable and function declarations use "let" keyword. *) (* Variable and function declarations use "let" keyword. *)
let x = 10 ;; let x = 10 ;;
(* Since OCaml uses type inference, you normally don't need to (* Since OCaml compiler infers types automatically, you normally don't need to
specify argument types explicitly. However, you can do it specify argument types explicitly. However, you can do it if you want or need to. *)
if you want or need to. *)
let inc_int (x: int) = x + 1 ;; let inc_int (x: int) = x + 1 ;;
(* You need to mark recursive function definitions as such with "rec" keyword. *) (* You need to mark recursive function definitions as such with "rec" keyword. *)
@@ -72,22 +72,13 @@ let rec factorial n =
else factorial n * factorial (n-1) else factorial n * factorial (n-1)
;; ;;
(* Function application usually doesn't need parantheses around arguments *) (* Function application usually doesn't need parentheses around arguments *)
let fact_5 = factorial 5 ;; let fact_5 = factorial 5 ;;
(* ...unless the argument is an expression *) (* ...unless the argument is an expression. *)
let fact_4 = factorial (5-1) ;; let fact_4 = factorial (5-1) ;;
let sqr2 = sqr (-2) ;; let sqr2 = sqr (-2) ;;
(* You can use multiple statements separated by semicolon in function body,
but the last expression becomes its return value. This is useful when
writing in imperative style. The simplest form of it is inserting a
debug print. *)
let print_and_return x =
print_endline (string_of_int x);
x
;;
(* Every function must have at least one argument. (* Every function must have at least one argument.
Since some funcions naturally don't take any arguments, there's Since some funcions naturally don't take any arguments, there's
"unit" type for it that has the only one value written as "()" *) "unit" type for it that has the only one value written as "()" *)
@@ -102,6 +93,15 @@ let make_inc x y = x + y ;; (* make_inc is int -> int -> int *)
let inc_2 = make_inc 2 ;; (* inc_2 is int -> int *) let inc_2 = make_inc 2 ;; (* inc_2 is int -> int *)
inc_2 3 ;; (* Evaluates to 5 *) inc_2 3 ;; (* Evaluates to 5 *)
(* You can use multiple expressions in function body.
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
form of it is inserting a debug print. *)
let print_and_return x =
print_endline (string_of_int x);
x
;;
(* Since OCaml is a functional language, it lacks "procedures". (* Since OCaml is a functional language, it lacks "procedures".
Every function must return something. So functions that Every function must return something. So functions that
@@ -117,7 +117,7 @@ let x = 10 in
let y = 20 in let y = 20 in
x + y ;; x + y ;;
(* Alternatively you can use "let ... in and ..." construct. (* Alternatively you can use "let ... and ... in" construct.
This is especially useful for mutually recursive functions, This is especially useful for mutually recursive functions,
with ordinary "let .. in" the compiler will complain about with ordinary "let .. in" the compiler will complain about
unbound values. unbound values.
@@ -127,28 +127,28 @@ x + y ;;
let a = 3 and b = 4 in a * b ;; let a = 3 and b = 4 in a * b ;;
(** Operators **) (*** Operators ***)
(* There is little distintion between operators and functions. (* There is little distintion between operators and functions.
Every operator can be called as a function. *) Every operator can be called as a function. *)
(+) 3 4 (* Same as 3 + 4 *) (+) 3 4 (* Same as 3 + 4 *)
(* There's a number of built-in operators. One of unusual features is (* There's a number of built-in operators. One unusual feature is
that OCaml doesn't just refrain from any implicit conversions that OCaml doesn't just refrain from any implicit conversions
between integers and floats, it also uses different operators between integers and floats, it also uses different operators
for floats. *) for floats. *)
12 + 3 ;; (* Integer addition *) 12 + 3 ;; (* Integer addition. *)
12.0 +. 3.0 ;; (* Floating point addition *) 12.0 +. 3.0 ;; (* Floating point addition. *)
12 / 3 ;; (* Integer division *) 12 / 3 ;; (* Integer division. *)
12.0 /. 3.0 ;; (* Floating point division *) 12.0 /. 3.0 ;; (* Floating point division. *)
5 mod 2 ;; (* Remainder *) 5 mod 2 ;; (* Remainder. *)
(* Unary minus is a notable exception, it's polymorphic. (* Unary minus is a notable exception, it's polymorphic.
However, it also has "pure" integer and float forms. *) However, it also has "pure" integer and float forms. *)
- 3 ;; (* Polymorphic, integer *) - 3 ;; (* Polymorphic, integer *)
- 4.5 ;; (* Polymorphicm float *) - 4.5 ;; (* Polymorphic, float *)
~- 3 (* Integer only *) ~- 3 (* Integer only *)
~- 3.4 (* Type error *) ~- 3.4 (* Type error *)
~-. 3.4 (* Float only *) ~-. 3.4 (* Float only *)
@@ -156,34 +156,34 @@ let a = 3 and b = 4 in a * b ;;
(* You can define your own operators or redefine existing ones. (* You can define your own operators or redefine existing ones.
Unlike SML or Haskell, only selected symbols can be used Unlike SML or Haskell, only selected symbols can be used
for operator names and first symbol defines associativity for operator names and first symbol defines associativity
and precedence rules. *) and precedence rules. *)
let (+) a b = a - b ;; (* Surprise maintenance programmers *) let (+) a b = a - b ;; (* Surprise maintenance programmers. *)
(* More useful: a reciprocal operator for floats. (* More useful: a reciprocal operator for floats.
Unary operators must start with "~" *) Unary operators must start with "~". *)
let (~/) x = 1.0 /. x ;; let (~/) x = 1.0 /. x ;;
~/4.0 (* = 0.25 *) ~/4.0 (* = 0.25 *)
(** Built-in datastructures *) (*** Built-in datastructures ***)
(* Lists are enclosed in square brackets, items are separated by (* Lists are enclosed in square brackets, items are separated by
semicolons. *) semicolons. *)
let my_list = [1; 2; 3] ;; let my_list = [1; 2; 3] ;;
(* Tuples are (optionally) enclosed in parantheses, items are separated (* Tuples are (optionally) enclosed in parentheses, items are separated
by commas *) by commas. *)
let first_tuple = 3, 4 ;; let first_tuple = 3, 4 ;; (* Has type "int * int". *)
let second_tuple = (4, 5) ;; let second_tuple = (4, 5) ;;
(* Corollary: if you try to separate list items by commas, you get a list (* Corollary: if you try to separate list items by commas, you get a list
with a tuple inside, probably not what you want. *) with a tuple inside, probably not what you want. *)
let bad_list = [1, 2] ;; (* Becomes [(1, 2)] *) let bad_list = [1, 2] ;; (* Becomes [(1, 2)] *)
(* You can access individual list items with List.nth function *) (* You can access individual list items with the List.nth function. *)
List.nth my_list 1 ;; List.nth my_list 1 ;;
(* You can add an item to the beginning of a list with "::" constructor (* You can add an item to the beginning of a list with the "::" constructor
often referred to as "cons". *) often referred to as "cons". *)
1 :: [2; 3] ;; (* Gives [1; 2; 3] *) 1 :: [2; 3] ;; (* Gives [1; 2; 3] *)
@@ -195,20 +195,20 @@ my_array.(0) ;;
(** Data types *) (*** User-defined data types ***)
(* You can define types with "type some_type =" construct. Like in this (* You can define types with the "type some_type =" construct. Like in this
useless type alias: *) useless type alias: *)
type my_int = int ;; type my_int = int ;;
(* More interesting types include so called type constructors. (* More interesting types include so called type constructors.
Constructors must start with a capital letter. *) Constructors must start with a capital letter. *)
type ml = OCaml | StandardML ;; type ml = OCaml | StandardML ;;
let lang = OCaml ;; (* Has type "ml" *) let lang = OCaml ;; (* Has type "ml". *)
(* Type constructors don't need to be empty. *) (* Type constructors don't need to be empty. *)
type my_number = PlusInfinity | MinusInfinity | Real of float ;; type my_number = PlusInfinity | MinusInfinity | Real of float ;;
let r0 = Real -3.4 ;; (* Has type "my_number" *) let r0 = Real (-3.4) ;; (* Has type "my_number". *)
(* Can be used to implement polymorphic arithmetics. *) (* Can be used to implement polymorphic arithmetics. *)
type number = Int of int | Float of float ;; type number = Int of int | Float of float ;;
@@ -222,13 +222,13 @@ let my_point = Point (2.0, 3.0) ;;
type 'a list_of_lists = 'a list list ;; type 'a list_of_lists = 'a list list ;;
type int_list_list = int list_of_lists ;; type int_list_list = int list_of_lists ;;
(* Types also can be recursive. Like in this type analogous to (* Types can also be recursive. Like in this type analogous to
built-in list of integers. *) built-in list of integers. *)
type my_int_list = EmptyList | IntList of int * my_int_list ;; type my_int_list = EmptyList | IntList of int * my_int_list ;;
let l = Cons (1, EmptyList) ;; let l = Cons (1, EmptyList) ;;
(** Pattern matching *) (*** Pattern matching ***)
(* Pattern matching is somewhat similar to switch statement in imperative (* Pattern matching is somewhat similar to switch statement in imperative
languages, but offers a lot more expressive power. languages, but offers a lot more expressive power.
@@ -237,20 +237,21 @@ let l = Cons (1, EmptyList) ;;
an argument against an exact value, a predicate, or a type constructor. The type system an argument against an exact value, a predicate, or a type constructor. The type system
is what makes it so powerful. *) is what makes it so powerful. *)
(* Matching exact values. "_" means "anything" *) (** Matching exact values. **)
let is_zero x = let is_zero x =
match x with match x with
| 0 -> true | 0 -> true
| _ -> false | _ -> false (* The "_" pattern means "anything else". *)
;; ;;
(* Alternatively, you can use "function" keyword *) (* Alternatively, you can use the "function" keyword. *)
let is_one x = function let is_one x = function
| 1 -> true | 1 -> true
| _ -> false | _ -> false
;; ;;
(* Matching predicates, aka "guarded pattern matching" *) (* Matching predicates, aka "guarded pattern matching". *)
let abs x = let abs x =
match x with match x with
| x when x < 0 -> -x | x when x < 0 -> -x
@@ -260,7 +261,7 @@ let abs x =
abs 5 ;; (* 5 *) abs 5 ;; (* 5 *)
abs (-5) (* 5 again *) abs (-5) (* 5 again *)
(* Matching type constructors *) (** Matching type constructors **)
type animal = Dog of string | Cat of string ;; type animal = Dog of string | Cat of string ;;
@@ -270,24 +271,23 @@ let say x =
| Cat x -> x ^ " says meow" | Cat x -> x ^ " says meow"
;; ;;
say (Cat "Fluffy") ;; (* "Fluffy says meow" *) say (Cat "Fluffy") ;; (* "Fluffy says meow". *)
(* Traversing data structures *) (** Traversing datastructures with pattern matching **)
(* Recursive types can be traversed with pattern matching easily. (* Recursive types can be traversed with pattern matching easily.
The cons thing ("::") that is used with built-in lists is actually a Let's see how we can traverse a datastructure of the built-in list type.
type constructor, except it can be used in infix form, unlike Even though the built-in cons ("::") looks like an infix operator, it's actually
user-defined constructors. So you can use it like this: *) a type constructor and can be matched like any other. *)
let rec sum_list l = let rec sum_list l =
match l with match l with
| [] -> 0 | [] -> 0
| head :: tail -> head + (sum_list tail) | head :: tail -> head + (sum_list tail)
;; ;;
sum_list [1; 2; 3] ;; sum_list [1; 2; 3] ;; (* Evaluates to 6 *)
(* Built-int syntax for cons obscures the structure a bit, so we'll make (* Built-in syntax for cons obscures the structure a bit, so we'll make
our own list for demonstration. *) our own list for demonstration. *)
type int_list = Nil | Cons of int * int_list ;; type int_list = Nil | Cons of int * int_list ;;