The translator preface

The translator first came into contact with OCaml language in class a year ago, but found that there were very few relevant Chinese textbooks. At the same time, the students combined the class content and their own understanding to write this course, so they took it and translated it for your reference. It is the first time for the translator to do the translation work, if there are mistakes and shortcomings are welcome to point out.

Link to the original tutorial: ocaml.gelez.xyz/

Tutorial source code: github.com/elegaanz/co…

Editor’s home page: github.com/elegaanz

Editor’s introduction

The purpose of this course is that you will be able to compare this course with INF201 (a first-year course for OCaml at Grenoble University). A lot of students will get bored with this course because of boredom, but in fact OCaml is a very interesting language. I don’t know if I can do any better, but trying is better than nothing. So this tutorial will only cover the basics of OCaml, and will be aimed at people who have already learned Python. Since this tutorial is based on the INF201 2020 course, it may not be completely updated in the event of future changes.

The following agreements will be used later:

1. The "additional" section is an interesting part of the course that is not included, and is recommended if you want to learn more about it. 2. Important concepts to understand will be highlighted in red.Copy the code

Note: It is recommended that you test the sample code as you read it, and fully understand what you have read before you move on to the next chapter. Also, it’s much easier to understand and digest new concepts if you can write your own examples.

I. Basic concepts

1. Briefly ocaml

In this chapter I will answer the following question: “What is OCaml?” “And” Why OCaml? If that doesn’t interest you, go to the next chapter.

The history of ocaml

L ‘LNRIA (French National Institute of Computer and Automation) is one of the leading organizations in France devoted to the field of computer research. In 1996, researchers at L ‘LnRIA published the first version of OCaml. From this came other languages: Caml Light, Caml, ML.

OCmal has been used in universities and businesses worldwide since it became an important language in the functional programming language spectrum.

A functional programming language?

Since you are reading this tutorial, you have no doubt taken INF101 (a Python course offered at Grenoble University in your first year) and learned the basics of programming in Python. However, Python is an imperative programming language (and it doesn’t matter if you haven’t taken a course in INF101, most programming languages are more or less imperative: C, C++, Java, C#, etc.). Imperative languages have explicit steps to solve a given problem, but functional programming languages do not.

In fact, in functional programming languages, all programming revolves around functions (surprisingly). So we tried to manipulate the data as much as possible, to solve our problems with functions. Specifically, we can, for example, use loops all the way through, replacing them with functions.

I think the question in your mind is, how do we implement programs that can’t use loops? Don’t worry, we’ll have other ways to do the same thing, using functions again!

Using functions to solve problems may be unfamiliar to you and a little confusing to beginners. But this is just a matter of convention, and in some cases it is more convenient to use functions than commands (especially when working with lists).

OCaml in real life

OCmal is a language that (thankfully) implements real programs. Among its users are Facebook, Jane Street (a Wall Street firm) and Airbus.

L ‘Lnria is also using OCmal to create Coq, a software that uses computers to test mathematical theorems.

Install OCmal

If you want to use it on your own PC, appendix 1 explains how to install OCmal.

Alternatively, try.ocamlpro.com/ can be used to test small programs online.

2. The first step of programming on OCAML

You can now write your first line of code on OCmal! First we need to open an interpreter (preferably uTOP, but it can also be OCAML or an online interpreter).

In the compiler, all commands are preceded by; The end (two semicolons). OCmal is then able to identify where the command ends and begin executing it. But if you are writing in a file, it is generally not required.

Try typing a simple calculation command (hit Enter to execute) :

 2 + 2;; 
Copy the code

In general, the interpreter returns the following:

- :int = 4
Copy the code

For the time being, let’s just focus on the right hand side of = : our formula runs successfully, 2 plus 2 equals 4. It’s a good start! And then you can try some other notation, like * or minus.

However, for some operators, there are a few minor details I’d like you to know:

  • / is used to calculate the quotient (similar to // in Python). So it’s going to be an integer.

  • Mod is analogous to the Python % used to calculate the remainder.

Without a doubt, the most confusing thing for you right now is that these operators don’t work with floating-point numbers (numbers with decimal points). For example, if you enter the following arithmetic expression, you will get an error message:

* From now on, I will not write; But don't forget to add * if necessary.)2.8 + 0.2
Copy the code

To understand why we get an error, we need to understand the definition of the expression and the type.

An expression is a piece of code that a computer can interpret and evaluate so that its value can be computed.

In OCaml, all or almost all of the code consists of expressions. But here’s an example from Python:

12 # This is an expression with a value of 12
12 + 7 # This is an expression with a value of 19. (Note here that this expression is made up of the simpler expressions 7 and 12.)
print("Hello!) # This is also an expression, although it has a value of None (no value)
a = 12 # This line is not an expression, "a = 12" is not a value, it is an instruction.
Copy the code

More generally, when you want to determine whether the statement in front of you is an expression, ask yourself: “Can I store this value in a variable?” From the following three examples, it is clear that for the first two lines, the answer is yes. But it doesn’t really work for the last row.

x = (12 + 7) # No problem
y = (print("Hello!)) # Although this may seem a bit odd since the value in this variable is < no value >, it works.
z = (a = 12) # Although this might seem logical in another case, "a = 12" is not a value and we cannot store it in a variable.
Copy the code

Now we’ll talk about types. A type is a piece of information about an expression that tells us what values can be stored in the expression. It’s kind of like the idea of a set in mathematics. No doubt we’ve seen several types in Python, such as ‘int’ or ‘float’ or ‘STR’. We still see these types in OCaml, but OCaml’s typing system is a step further than Python’s. In OCaml, all expressions have their defined types: we call this a statically typed language.

But all of this doesn’t explain why adding two decimals causes an error. The reason is that the operator + in OCaml applies to expressions that are flanked by ints; otherwise it does not. The same is true for -, *, /, and mods. For floating point numbers, we have different operators: +., -., *., /., and mod_float.

But why complicate it? Python works fine without distinguishing between the two operators. Why not OCaml?

OCaml takes types very seriously, and it needs to know the type of an expression all the time. It can’t be ambiguous about this. Again, this ensures that there are no errors in the line of code before it is run. Run the following statement in Python:

liste = [1.2.3]
liste + "Oups" Add a list to a text? 🤔 ️
Copy the code

Python is not as strict as OCaml in terms of type, it runs the program without asking questions, and it does not show errors when problem lines are run. In this example, the problem can be found quickly, but imagine the same problem in the middle of hundreds of lines of code, in the middle of extremely complex functions… In short, finding the source of the error is a nightmare!

In OCaml, if you try to do this type of operation, you’ll get a type error right before the code runs, so you can avoid a lot of errors ahead of time!

But in order to validate these types, OCaml needs to know the type of each expression. In this task, it helps to use the operators correctly: addition + for ints, addition +. Applies to float types. That’s why we can’t use the same operator everywhere!

3. More types!

As we saw in the last section, OCaml has an integer of type int and a floating point of type float, just like in Python! The only difference is that there are different operators for different types.

int float
example 2.2 - 2..1e3.3.14
add + +.
subtraction - -.
The multiplication * *.
division / /.
Strives for the remainder mod mod_float

Of course there are other basic types of OCaml.

Boolean (Boolean)

Bool types also exist in OCaml and operate in a similar way to Python. The biggest difference is that we no longer capitalize true and false. Although the logical operators are not written the same way, they work the same way.

Logic and &&
Logic or ||
Logic is not not

The comparison operators are almost the same as in Python: <, <=, >, >=. Only the equal and not equal signs are changed: in OCaml, we will use = and <> (== and! = also exists, but not in the intended sense). The advantage of comparison operators is that the expression can be of the same type as long as the left and right sides are of the same type, regardless of type (we can compare two ints or two floats, but we can’t compare an int to a float).

The text

In OCaml, you need to distinguish between single characters and strings.

  • First of all,charThe type is written between single quotes: ‘a’.
  • Second,stringThe type is written between double quotes: “Bonjour!” .

Notice that ‘a’ is not the same as ‘a’. Also, unlike Python, which supports ASCII tables and Unicode (which supports tonal letters, other characters in the alphabet, emojis, and so on), OCaml has little Unicode support: so it’s best to avoid entering tonal letters into text when using OCaml.

In addition, just as + applies between two integers, the operator used to concatenate two strings is ^.

From one type to another

OCaml provides several functions to switch different types. The names of these functions have a fixed format DEST_of_ORIG, with DEST being the target type and ORIG being the original type. For example, to switch from float to int, we would use int_of_float.

You don’t know how to call a function yet, but that’s our goal in the next section!

4. The function

As we mentioned earlier, functions are at the heart of the OCaml language. Next we’ll learn how to create and call functions.

Create a function

In OCaml, we use the keyword let to define a function:

let f x y = x + y
Copy the code

To better understand what the lines of code mean, here’s the same program in Python:

def f(x, y) :
    return x + y
Copy the code

Here we note a few differences:

  • Arguments are not written in parentheses, but directly after the function name;
  • The parameters are separated by Spaces instead of commas.
  • The body of the function is a symbol=Start;
  • The function body contains only one expression, not a series of instructions.
  • The only instruction is always the result returned by the function.

This minimalist syntax may seem strange at first, but we’ll soon get used to it and find it handy as we dig deeper into OCaml (see the add-on).

If we enter the following command in the OCaml interpreter, we will get the type of the function:

f
Copy the code

We can see that this function is of type int -> int -> int. The thing to know about this comment is that the first two types are the type of the argument, and the last is the type of the value returned. Here, the arguments x and y are int, and their sum is int. If you want to know why you chose a less intuitive comment, we’ll discuss that in the currying section.

A practical practice (and one that is also required in school exams) is to explicitly annotate the type of function. For this, we use syntax (parameter: type) instead of parameters. For the returned value, we use :type before = to indicate its type.

let f (x : int) (y : int) : int = x + y
Copy the code

This comment is longer, but it has the advantage of explicitly showing the types of different expressions. Again, this makes it easier for us to understand the function, because we can clearly see what the parameters and return values can take.

Tip: The definition of multiplication

We can also define several functions at once by separating their declarations with and (note: not ampersand).

let identite x = x and carre x = x * x and cube x = x * x * x
Copy the code

But in this syntax, we cannot use the function at the top of the line to define the function at the bottom. For example, we cannot write like this:

let carre x = x * x and cube x = (carre x) * x
Copy the code

Because when we define cube, the function carre does not exist in the environment (it has not yet been run).

Call a function

Now that we have our first function (don’t hesitate to create others), let’s see how we call it.

f 1 2
Copy the code

In this way! In general, the interpreter will return 3. If you need to use more complex arguments, you can use parentheses:

f (4 * 3) 7
Copy the code

And variables?

In fact, the concept of variables does not exist in OCaml 1. However, we can have function constants without arguments.

let pi = 3.1415
Copy the code

In addition, we can use expressions to restrict functions, so we can define a function only in the local way. To do this, after declaring the function, we add the keyword in and an expression so that we can use the function we just defined.

let cube x = x * x * x in (cube 2) + (cube 3)

(* without defining the cube, we can write: *)
(2 * 2 * 2) + (3 * 3 * 3)
Copy the code

Usually we will wrap the lines after the in to make the code easier to read. Similarly, we can nest let and let/in:

(* This function calculates the norm in the plane, given the coordinates *)
let norme (X : float) (y : float) : float =
    let carre a = a * a in
    let x_carre = carre x in
    let y_carre = carre y in
    sqrt (x_carre + y_carre) (* SQRT is the base function in OCaml *)
Copy the code

5. Practice after class

To verify that you have understood what has been said so far, try answering the following questions. If you get it right, your answer will change from red to green. (Because the editor wrote the code on the web, but the mining does not support this format, the translator changed it slightly. You can test it by opening the source page at the beginning.

What are the types of the following expressions? If the type does not hold, the input is incorrect.

2 + 2
Copy the code
< Answer point me >
    int
Copy the code
2e3 +. 2.5 *. (float_of_int 4)
Copy the code
Let me > <
    float
Copy the code
'H'
Copy the code
Let me > <
    char
Copy the code
12 > 3 && 7
Copy the code
Let me > <
errorCopy the code
"You" ^ "Good" ^ "!"
Copy the code
Let me > <
    string
Copy the code
42 > 12 || 19 > 38
Copy the code
Let me > <
    bool
Copy the code
let ajouter x y = x + y

ajouter (* We're asking for the type of ajouter *)
Copy the code
Let me > <
    int -> int -> int
Copy the code
'A' + 3
Copy the code
Let me > <
errorCopy the code
(* We assume that 'x' and 'y' are previously defined constants * but we don't assign values to them * and: this expression is not of an error type *) 
    x +. (y *. y)
Copy the code
Let me > <
    float
Copy the code

Are the following Boolean expressions true or false?

42 > 12 || 19 > 38
Copy the code
Let me > <
    true
Copy the code
4 * 5 + 2 = 28
Copy the code
Let me > <
    false
Copy the code
'a' < 'e'
Copy the code
Let me > <
    true
Copy the code
let x = 15
x > 2 && x < 17
Copy the code
Let me > <
    true
Copy the code
"Zoe." > "Alice"
Copy the code
Let me > <
    true
Copy the code

What should be put in ___ so that the value of rusultat is 38?

let ____ = (2 * x * x) + (3 * x) + 11
let resultat = polynome 3
Copy the code
Let me > <
    (polynome x) 或 (polynome (x : int))
Copy the code

If you want to try some more, here’s a real problem set.

Implement the following functions:

- Calculate the cube of a floating point number 'x'; - A function that takes three arguments, a, b, and ε, and determines whether a is equal to b for a given ε. To simplify this task, we default that 'a' is always greater than 'b'; - This function takes a character and an integer and verifies whether the encoding of the character corresponds to the integer in the ASCII table. You can first test the following character 'A', which corresponds to '65' in the ASCII table.Copy the code
Let me > <
   let cube (x : float) : float = x * x * x
   
   
   let egal (a : float) (b : float) (epsilon : float) : bool =
   
       let diff = a -. b in
       
       diff < epsilon
   
   
   let est_ascii (c : char) (i : int) : bool =
       (int_of_char c) = i
       
Copy the code

When you’re done, you can move on to the next chapter. If you have a lot of questions, the best thing to do is to reread chapter 1 and test the code in all the examples yourself, and then give yourself some more examples. If something is not clear and you need clarification, email this email address.

ocaml @ gelez . xyz


  1. In fact, this is similar to the concept of ‘reference’, but we will avoid using it and will not cover it in this tutorial. ↩