[TOC]

# 1. BASIC DATA TYPES: int, bool

Rich type system and polymorphism in ocaml. Types are *infered* not declared.

**Basic types**: int, bool, float, string, char, ...

### int

value: $-2^{62}$ ~ $2^{62}-1$ on 64-bit machines.

ops: `+, -, *, /, mod`

(reminder: `/`

is integer division)

```
# 3+2*4-1;;
- : int = 10
# 5/2;;
- : int = 2
# -5 mod 3;;
- : int = -2
```

### bool

values: `true, false`

ops: `&&,||, not`

comparison ops: `<, >, =, <=, =>, <>`

note 1: comparisons must have the *same type* of operands)
note 2: equal test is `=`

, `=`

is NOT assigment. `==`

exists but is for something else...

```
# true && (1<7);;
- : bool = true
# 1.0 < 7;;
Error: This expression has type int but an expression was expected of type
float
# 5 > "hello";;
Error: This expression has type string but an expression was expected of type
int
# 3=3;;
- : bool = true
# 3==3;;
- : bool = true
# 3<3.0;;
Error: This expression has type float but an expression was expected of type
int
# 3.0 < 3.0;;
- : bool = false
```

# 2. MORE DATA TYPES: float, char, string

### float

value: must written with a dot (`5.0`

, `5.`

), or exponential (`5e3`

, `6e-9`

)
ops: *also have a dot in the end* `+.`

, `-.`

, `*.`

, `/.`

functions: `sqrt, sin, cos, ceil, floor, ...`

```
# 3.0 +. 1e10;;
- : float = 10000000003.
# 2 + 3.0;;
Error: This expression has type float but an expression was expected of type
int
# 3. +. 2.0;;
- : float = 5.
```

**All basic types are disjoint**: no value belongs to 2 different basic types, **no implicit conversion. **

conversion functions in both directions:

`float_of_int`

: int -> float`int_of_float`

: float -> int

```
# float_of_int(2);;
- : float = 2.
# int_of_float(2.4);;
- : int = 2
# float_of_int 2;;
- : float = 2.
# int_of_float 2.8;;
- : int = 2
```

**Parentheses only necessary to indicate structure**.

### char

values: 256 chars (0~255), can be written as '`a`

' or '`\087`

'
conversion functions (char ↔ int):

`Char.chr`

: int ->char`Char.code`

: char -> int

```
# Char.code 'A';;
- : int = 65
# Char.code '\122';;
- : int = 122
# Char.chr 233;;
- : char = '\233'
# Char.chr 65;;
- : char = 'A'
# Char.chr (Char.code 'B');;
- : char = 'B'
```

### string

values: written between `""`

ops: `^`

for string concatenation
functions: `String.length, int_of_string, float_of_string, String.get(s,i) ...`

```
# "abc" ^ "def";;
- : string = "abcdef"
# String.length "1234";;
- : int = 4
# int_of_string "123";;
- : int = 123
# int_of_string "123a";;
Exception: Failure "int_of_string".
# string_of_int 123;;
- : string = "123"
# String.get "abc" 1;;
- : char = 'b'
```

# 3. EXPRESSIONS: if-then-else, func-applications and operators

**expressions** are used to compute values.

### conditional expr

`if... then... else...`

⇒ this gives an **expression**, not an **instruction**.

*An expression always have a type*, type of the if-then-else expression is the type of the expressions in then and else, *which must be the same*.

If the `else`

is missing → there is a default value, to be discussed later

```
# if 1<2 then 8 else 9;;
- : int = 8
# if 6=8 then 1 else 8;;
- : int = 8
# if 6=8 then 1 else 8.;;
Error: This expression has type float but an expression was expected of type
int
# if(if 1=1 then 2=2 else 3>2) then 2<3 else 3<2;;
- : bool = true
```

### function application

again, `()`

are **not needed** unless indicate structure, and **parentheses are NOT function applications...**

```
# String.get;;
- : string -> int -> char = <fun>
# String.get "abcde" 2;;
- : char = 'c'
# String.get ("Hello"^"world") (3+2);;
- : char = 'w'
# String.get (string_of_int 65) (int_of_string "0");;
- : char = '6'
# String.get("hello", 2);;
Error: This expression has type 'a * 'b
but an expression was expected of type string
```

### Polymorphic operators

Some ops have polymorphic(generic) types, like `>`

: '`a → 'a → bool`

Here the '`a`

is a *type variable, *can be instantiated by any type*.*

```
# 12 > 23.0;;
Error: This expression has type float but an expression was expected of type
int
# 'a' > 'b';;
- : bool = false
# "hello" > "world";;
- : bool = false
```

# 4. DEFINITIONS

**definition**s are used to give names to values, in ocaml there are *global* defs and *local* defs.

### global definition

effective for rest of session
syntax: `let name = expr`

once set, the value of the identifier never changes.

```
# let x = 2+3;;
val x : int = 5
# let y = 2*x;;
val y : int = 10
# let x = 3;; # **the old definition of x will be shadowed**
val x : int = 3
# x = x+1;;
- : bool = false
```

### local definition

naming within a delimited scope
syntax: `let name = expr1 in expr2`

the scope of the identifier is `expr2`

, the result's value is also *expr2's value*. *So the identifier should appear in expr2*.

```
# let x = 9 in 2*x;;
- : int = 18
# x;; # x is not in global scope
Error: Unbound value x
# let y = x+1 in y/3;;
Error: Unbound value x
# let x = 17;; # now x is global
val x : int = 17
# let y = x+1 in y/3;;
- : int = 6
```

local defs can be nested:

```
# let x = 4 in
let y = x+1 in
let x = 2*y in x;;
Error: Syntax error
# let x = 4 in
let y = x+1 in
let x=2*y in x;;
- : int = 10
# let x = 4 in
(let x=17 in x+1) + x;;
- : int = 22
```

### Simultaneous Definitions

can assign 2 identifiers in the same line:

```
# let x1=2 and x2=3-3;;
val x1 : int = 2
val x2 : int = 0
```

**Note:** `expr`

is evaluated w.r.t. the value bindings *before* the `let`

.

```
# let x=2 in
let y=x+1 in (*y=2+1*)
x*y;;
- : int = 6
# let x=1;;
val x : int = 1
# let x=2 and y=x+1 in (*y=1+1 because the binding for x before the let is 1!*)
x*y;;
- : int = 4
```

# 5. FUNCTIONS

### func definition

global function (with 1 argument) def : `let f x = expr`

local def: `let f x = expr1 in expr2`

```
# let f x = x+1;;
val f : int -> int = <fun>
# f 17;;
- : int = 18
# let g y = 2*y
in g 42;;
- : int = 84
# f f 1;; (* interpreted as apply 2 argments to f, need parentheses here*)
Error: This function has type int -> int
It is applied to too many arguments; maybe you forgot a `;'.
# f (f 1);;
- : int = 3
```

### lexical scoping

def.

lexical scopingidentifiers(names) used in function body refers to the namesthatare visibleat the moment of function definition.def.

dynamic scopingnames refer to names that are visibleat the moment of function invocation.

```
# let f x = x+1 in
let g y = f (f y) in (*here f is the f defined above, which is visible at the moment of g's declaration*)
let f x = 2*2 in (*this f is visible after g's declaration, it is visible when g is invocated*)
g 5;; (*g uses the first f*)
Warning 26: unused variable f.
- : int = 7
(*the same is true for global scoping*)
# let f x = x+1;;
val f : int -> int = <fun>
# let g y = f (f y);;
val g : int -> int = <fun>
# let f x = 2*x;;
val f : int -> int = <fun>
# g 5;;
- : int = 7
```

### identifiers are NOT variables

A name(identifier) can be *hidden* (the value is NOT *changed*) by a new definition of the same name.

The hidden identifier can be accessed with static(lexical) binding:

```
# let a = 1;;
val a : int = 1
# let f x = x+a;;
val f : int -> int = <fun>
# f 2 ;;
- : int = 3
# let a = 73;;
val a : int = 73
# f 2;; (*f still uses a's value as 2, the old value of a is NOT changed, it's hidden --closure? *)
- : int = 3
```

# 6. RECURSION

rec functions are natural on recursively defined data structures.

example: fact(n)

### recursive definition

using the `f`

in let's `expr`

will cause pb as `f`

refers to the previous value of `f`

. ⇒ use key word `rec`

.

```
# let fact n = if n<=1 then 1 else n*fact(n-1);;
Error: Unbound value fact
# let rec fact n = if n<=1 then 1 else n*fact(n-1);;
val fact : int -> int = <fun>
# fact 10;;
- : int = 3628800
```

### mutually recursive function

ex. 2 funcs calling each other recursively

⇒ *use simultaneous defs* (`let...and...`

):

```
# let rec even x = if x=0 then true else odd(x-1)
and odd x = if x=0 then false else even(x-1);;
val even : int -> bool = <fun>
val odd : int -> bool = <fun>
# even 17;;
- : bool = false
# odd 10;;
- : bool = false
```

# exercices

```
let multiple_of n d =
(n mod d) == 0;;
let integer_square_root n =
let sqr = sqrt (float_of_int n) in
int_of_float sqr;
let rec gcd n m =
let big = max n m and small = min n m in
let r = big mod small in
if r=0 then small
else gcd r small;;
let rec multiple_upto n r =
if r<2 then false
else if multiple_of n r then true
else multiple_upto n (r-1);;
let is_prime n =
if n<=1 then false
else not (multiple_upto n (n-1));;
```

#### Part 2 of series «Introduction to Functional Programming in OCaml»：

- [OCaml MOOC] week0: intro and overview
- [OCaml MOOC] week1: BASIC TYPES, DEFINITIONS AND FUNCTIONS
- [OCaml MOOC] week2: BASIC DATA STRUCTURES
- [OCaml MOOC] week3: MORE ADVANCED DATA STRUCTURES
- [OCaml MOOC] week4: HIGHER ORDER FUNCTIONS
- [OCaml MOOC] week5: EXCEPTIONS, INPUT OUTPUT AND IMPERATIVE CONSTRUCTS
- [OCaml MOOC] week6: MODULES AND DATA ABSTRACTION

## Disqus 留言