Goals

  • Discover the OCaml toplevel interpreter.
  • Get familiar with the syntax, basic types, and the top-level let.

Requirements

➪ You have already completed the OCaml - Setup.

Mission 1

Basic types, the top-level let

Launch utop which is an ocaml interpreter, or use an online interpreter, like Try OCaml.

Comments

Comments in OCaml are written like this: (* This is a comment. *)
Unlike in C or Java, OCaml comments can be nested:(* This comment contains (* a nested comment *) inside. *)
(You may ask yourself why).

Int

  • Evaluate an integer of your choice : 42 ;; (42 been the only reasonable choice)
  • Evaluate a computation of your choice : (5000 + 838) / 139 ;;
  • Bind a value to a constant x using a top-level let: let x = 100 + 99 ;;
    In the interpreter's output, you recognise: the expression type, the value, the constant name.
  • What is the type of the + operator?(+) ;;
    It is a function expecting two arguments of type int and returning an int.
    • In C or Java, it would be written int plus(a,b: int).
    • In Ocaml, it is int → int → int.
  • In the interpreter, look at the type of the abs function (absolute value). It is a function expecting one argument of type int and returning an int.
    The predefined functions can be found in the manual.
  • In Ocaml, functions are normal values (we say that functions are first class citizens). We can bind a function to a constant, as any value:let add = (+) ;;
  • To apply a function, arguments are just passed by juxtaposition (this is a function application):add 10 25 ;; abs (-10) ;;
  • Try to apply the function to an argument with the wrong type:add 10 true ;;
    The typechecker complains. This is a type error.
  • All of the following are equivalent:let a = 10 + 25 let b = add 10 25 let c = add (10) (25) let d = (add 10 25) let e = (+) 10 25 let f = ((+) 10 25) ;;
    Exercise : Application
    • Write an expression that computes 10 + 20 + 30 by using only the add function (not the + operator).
    • Similarly, compute 10 + abs (10 + -20) , not using +.
    • Explain the type error produced by: abs -10 , instead of abs (-10) which is correct.
  • Finally, try to apply partially a two-argument function: let f = add 100 ;;
    The result, f, is a function expecting another argument of type int and returning a result of type int.
    Try it: f 5 ;; f 99 ;;
    • f is called a closure, that is a partially applied function (some of its arguments are already known).
    • The function add is actually a function expecting a first argument of type int and returning another function : int → (int → int).
      This is called currying, add is a curried function.
    • Compare the types of: add ;; add 20 ;; add 20 30 ;;
    • We will study this again later.

Float

  • As usual, floats are written with a dot: 3.0
  • Floats and ints do not mix: 3.0 + 3
  • The + operator is defined for integers only. For floats, use these operators: 3.0 +. 1.5 ;; 3.0 -. 1.5 ;; 3.0 *. 1.5 ;; 3.0 /. 1.5 ;;
    Find their types: (+.) ;;
  • Conversions are performed with: float_of_int ;; int_of_float ;;
    (Look at the types in the interpreter.)
  • It is sometimes convenient to rename those operators, by using a standard let binding:
    let foi = float_of_int ;; let iof = int_of_float ;; 1.5 *. foi 4 +. foi 12 ;;
    See all the float functions in the manual.

Bool, IF

  • The type bool contains two values: true ;; false ;;
  • As expected, comparisons return booleans: let b = (10 < 20) ;; let c = (10 = 20) ;;
    Note: these operators < , > , = are infix functions too.
  • Find in the interpreter the types of: not , && , || . (two of them are infix)
  • Booleans can be used in if expressions.
    In OCaml, if are not statements, but expressions. Thus, they can occur anywhere, if they provide a type compatible with the context:100 + (if b then -1 else 50) * 2 ;; let msg = if c then "AAA" else "BBB" ;;
    The first if is used with type int, the second if is used with type string.
  • What is the type of this if expression? let u = 10 * (if b || c then (+) else (-)) 50 25 ;;
    Guess the result.
  • The else part can be omitted, only if the if is used with type unit (the type unit is explained below) :
    if u = 0 then print_string "Bla !" ;;
  • In the interpreter, find the type of the < operator.
    It is a polymorphic type: it can compare any pair of values, not only ints.
    The type 'a (a notation for 'alpha') means anything.
    Exercise : Comparisons
    Guess the types of: let a = (<) ;; let b = (<) 10 ;; let c = (<) 10 20 ;; let d = (<) "aaa" ;; let e = (<) "aaa" "aab" ;; let f = (<) "aaa" 30 ;; let g = (<) 1.0 ;;
    (Check your guess in the interpreter.)
    • Which of these expressions are closures?
    • Which of these expressions are functions?
    • Which of these expressions are values?

String, char

  • Strings are written "like this" and characters 'a' .
    Notice that string is the type of immutable strings, whereas mutable strings have type bytes.
  • Concatenation : "foo" ^ "bar"
    (What is the type of the concatenation operator? )
  • Read a byte in the string: let s = "abc" ;; s.[0] ;;
  • Although s.[0] returns a char, it is actually a single byte, not a real utf character. Read the forbidden story of strings, above, to understand why.

Unit, print

  • To print messages on the standard output, one can use: print_endline "Ok." ;; print_int 50 ;;
    Both expressions are of type unit.
  • The type unit is equivalent to void in C or Java.
    There exists only one value of type unit : () ;;
  • Look at the type of print_int
    It is a function which always return the value () , hence the type int → unit
    Exercise : Unit as an argument
    • Look at the type of print_newline
    • Try to apply it. (An empty line should be printed, and nothing else.)
  • Now, the real stuff: the Printf module.
    Look at this example: Printf.printf "An int %d, a string %s, another int %d, a float %.3f \n %!" 99 "ok" 888 4.0 ;;
    The %! occurring at the end of every message means FLUSH.
    Exercise : Printf
    Guess the types of: Printf.printf "Once %d %!" ;; Printf.printf "upon %!" ;; Printf.printf "a %d %!" 99 ;; Printf.printf "midnight %d %d %!" 98 97 ;; Printf.printf "dreary %d %d %!" 96 ;;

Tuples

After the ground types int, float, string, bool and unit, we get interested in composite types.

  • Remember what is a cartesian product? The set ℤ×ℤ contains pairs of two integers, such as (3, 8).
    The set ℝ×ℤ×ℕ contains triples such as (1.5, -12, 40).
  • In OCaml, tuples (cartesian products) are built-in. Just check the types of the following expressions:
    (2, 4) ;; (1.5, "ok") ;; (false, true, -10) ;; ( (), true, () ) ;;
    The parentheses are not always necessary: 2, 4 ;;
  • Note that (1, 2, 3) is not equivalent to (1, (2,3)) (compare both types).
  • Functions are really first-class citizens:
    let add = (+) ;; (add, abs) ;;
    It is a pair of functions (having different types).
    Exercise : Tuples
    • Guess the types of: ( 0 < 1, false) ;; ( add, add 1, add 1 2) ;;
    • What happens with (1,2) + (3,4) ?
  • Tuples can be used to define several variables at once:
    let (a,b,c) = (100, 200, 300) let (myplus, myminus) = ( (+), (-) ) These two lines define five variables a, b, c, myplus, myminus

Lists

OCaml has built-in lists.

  • [] the empty list.
  • let l1 = [ 5 ; 4 ; 3 ; 2 ; 1 ] ;; a list with the given elements.
    All elements must have the same type. Try [ 1 ; true ]
  • A list of ints has type int list.
  • let l2 = 7 :: 6 :: l1 ;; creating a new list with two more elements at the head.
    Check that l1 is unchanged. In OCaml, lists are immutable.
  • l1 :: l1 ;; is incorrect. The cons operator (::) appends one element to a list of elements. It cannot append l1 to a list of ints.
  • A list can contain another list : [ l1 ] ;;
    Guess the type of: l1 :: [l1] ;;
    Exercise : Inner lists
    Guess the types of: [l2] :: l1 ;; [l1] :: [l2] ;; l2 :: [l1] ;; l1 :: l2 ;; [ l1 ; l2 ] ;; [ l1 ; [l2] ] ;;
  • There exist functions to take the first element of a list, to take the tail of a list, and to test if a list is empty. However, OCaml programmers do not use such function, since we can use pattern matching instead (to be seen later).
Exercise : Lists
  • Guess the types of: 1 :: [] ;; [ (+) ; (-) ] ;; (<) 5 :: (=) 3 :: [ (>) 0 ] ;;
  • What is the type of add 10 [ 1 ; 2 ; 3 ] ?
  • What is the difference between [ 1 ; 2 ; 3 ] and [ 1, 2, 3 ] ?
    Get convinced that the latter is actually a singleton list.
  • Find an OCaml expression that has type: (int * bool) list * int list list
    This type should be understood as (int * bool) list * (int list list).

Top-level LET

  • So far, you have evaluated programs of the form
    some-expression ;; or let name = some-expression ;;
    This let binding is called a top-level expression.
    You can use it at the root level of your program, but not inside a structure.
  • For instance, you cannot use a top-level let inside a list: [ 4 ; Forbiddenlet x = 5 ; 6 ]
    On the contrary, a if is a standard expression which can be used anywhere.
    For example, [ 4 ; if 2 < 3 then 5 else -5 ; 6 ] is a 3-element list.
    Exercise : Top-level let
    Which of the following are valid programs? and what is the type of the result?
    (3, let y = 12) ;; let y = 10 ;; (y, y, true) ;; let z = [ 1 ; y ] ;; let w = 8 :: z ;; let u = z :: z ;; 8 :: let v = [ 3 ; 4 ] ;;
  • Vocabulary: in a top-level expression such as let x = 10 ;; , we say that x is a variable (even though its value is actually constant).
    This is actually a variable in the mathematical sense, like a variable in an equation.
  • Redefining let variables: try to guess the result of the following.
    let x = 100 ;; let y = x ;; let x = true ;; y ;; let x = y ;; let y = "ok" ;; x ;; y ;; (* Now, pay attention. *) let (x,y) = (y,x) ;; (* What if we do it twice? *) let (x,y) = (y,x) ;;
    Let variables can be redefined: the previous definition is simply hidden. It is not an assignment (unlike x = 20 ; in C or Java).
  • Note that ;; means precisely: I have finished writing, please evaluate my piece of program.
    You may remove ;; when it is followed by a top-level let.
    In the next lessons, we will usually omit the ;;

Outcomes

Once the mission is completed, you must be able to:

  • Evaluate expressions in the toplevel.
  • Understand basic type errors.
  • Handle composite types such as lists or tuples.
  • Use the following words in everyday conversation: infix operator, closure, expression, top-level expression.