We have already met the conditional control structure on page ??, whose abbreviated form

#let`n`

`=`

`ref`

`1`

`;;`

`val n : int ref = {contents=1}`

#if

`!`

n

`>`

`0`

then`n`

`:=`

`!`

n

`-`

`1`

`;;`

`- : unit = ()`

A sequence of expressions is itself an expression, whose value is that of the last expression in the sequence (here,

# print_string

`"2 = "`

;

`1`

`+`

`1`

`;;`

`2 = - : int = 2`

With side-effects, we get back the usual construction of imperative languages.

#let`x`

`=`

`ref`

`1`

`;;`

`val x : int ref = {contents=1}`

# x`:=!`

x`+`

`1`

`;`

`x`

`:=!`

x`*`

`4`

`;`

`!`

x`;;`

`- : int = 8`

As the value preceding a semicolon is discarded, Objective CAML gives a warning when it is not of type

# print_int

`1`

;

`2`

`;`

`3`

`;;`

`Characters 14-15:`

`Warning: this expression should have type unit.`

`1- : int = 3`

To avoid this message, you can use the function

# print_int

`1`

;`ignore`

`2`

;

`3`

`;;`

`1- : int = 3`

A different message is obtained if the value has a functional type, as Objective CAML suspects that you have forgotten a parameter of a function.

#let`g`

`x`

`y`

`=`

`x`

`:=`

`y`

`;;`

`val g : 'a ref -> 'a -> unit = <fun>`

#let`a`

`=`

`ref`

`1`

`0`

;;`val a : int ref = {contents=10}`

#let`u`

`=`

`1`

in`g`

`a`

`;`

`g`

`a`

`u`

`;;`

`Characters 13-16:`

`Warning: this function application is partial,`

`maybe some arguments are missing.`

`- : unit = ()`

#let`u`

`=`

`!`

a

in`ignore`

(g`a`

)`;`

`g`

`a`

`u`

`;;`

`- : unit = ()`

As a general rule we parenthesize sequences to clarify their scope. Syntactically, parenthesizing can take two forms:

We can now write the Higher/Lower program from page ?? more naturally:

#let

rec`hilo`

`n`

`=`

`print_string`

`"type a number: "`

;

let`i`

`=`

`read_int`

`()`

in

if`i`

`=`

`n`

then`print_string`

`"BRAVO\n\n"`

else

begin

if`i`

`<`

`n`

then`print_string`

`"Higher\n"`

else`print_string`

`"Lower\n"`

`;`

`hilo`

`n`

end`;;`

`val hilo : int -> unit = <fun>`

The

for name = expr_{1} to
expr_{2} do expr_{3} done |

for name = expr_{1} downto
expr_{2} do expr_{3} done |

The expressions

#for`i`

`=`

`1`

to

`1`

`0`

do

`print_int`

`i;`

`print_string`

`" "`

done;`print_newline()`

`;;`

`1 2 3 4 5 6 7 8 9 10`

`- : unit = ()`

#for`i`

`=`

`1`

`0`

downto

`1`

do`print_int`

`i;`

`print_string`

`" "`

done;`print_newline()`

`;;`

`10 9 8 7 6 5 4 3 2 1`

`- : unit = ()`

The non-bounded loop is the ``while'' loop whose syntax is:

The expression

#let`r`

`=`

`ref`

`1`

in

while

`!`

r

`<`

`1`

`1`

do

`print_int`

`!`

r`;`

`print_string`

`" "`

`;`

`r`

`:=`

`!`

r`+`

`1`

done`;;`

`1 2 3 4 5 6 7 8 9 10 - : unit = ()`

It is important to understand that loops are expressions like the previous ones which calculate the value

Note that the string

#let`f`

`()`

`=`

`print_string`

`"-- end\n"`

`;;`

`val f : unit -> unit = <fun>`

# f

(for`i`

`=`

`1`

to

`1`

`0`

do

`print_int`

`i;`

`print_string`

`" "`

done)`;;`

`1 2 3 4 5 6 7 8 9 10 -- end`

`- : unit = ()`

`"-- end\n"`

is output after
the integers from 1 to 10 have been printed: this is a demonstration
that the arguments (here the loop) are evaluated before being
passed to the function.In imperative programming, the body of a loop (

#let`s`

`=`

`[`

`5`

;

`4`

;

`3`

;

`2`

;

`1`

;

`0`

`]`

`;;`

`val s : int list = [5; 4; 3; 2; 1; 0]`

#

for`i`

`=`

`0`

to

`5`

do`List.tl`

`s`

done`;;`

`Characters 17-26:`

`Warning: this expression should have type unit.`

`- : unit = ()`

The field

#type

'a`stack`

`=`

`{`

mutable`ind`

`:`

int;`size`

`:`

int;

mutable`elts`

`:`

'a`array`

`}`

`;;`

The operations on these stacks will be

This function cannot create a non-empty array, because you would have to provide it with the value with which to construct it. This is why the field

#let`init_stack`

`n`

`=`

`{ind`

`=`

`0`

;`size`

`=`

n;`elts`

`=[||]}`

`;;`

`val init_stack : int -> 'a stack = <fun>`

Two exceptions are declared to guard against attempts to pop an empty stack or to add an element to a full stack. They are used in the functions

#exception`Stack_empty`

`;;`

#exception`Stack_full`

`;;`

#let`pop`

`p`

`=`

if`p`

`.`

ind

`=`

`0`

then`raise`

`Stack_empty`

else

(p`.`

ind

`<-`

`p`

`.`

ind

`-`

`1`

;`p`

`.`

elts`.`

(p`.`

ind))`;;`

`val pop : 'a stack -> 'a = <fun>`

#let`push`

`e`

`p`

`=`

if`p`

`.`

elts

`=`

`[||]`

then

(p`.`

elts

`<-`

`Array.create`

`p`

`.`

size`e;`

`p`

`.`

ind

`<-`

`1`

)

else

if`p`

`.`

ind

`>=`

`p`

`.`

size

then`raise`

`Stack_full`

else

(p`.`

elts`.`

(p`.`

ind)

`<-`

`e;`

`p`

`.`

ind

`<-`

`p`

`.`

ind

`+`

`1`

)`;;`

`val push : 'a -> 'a stack -> unit = <fun>`

Here is a small example of the use of this data structure:

#let`p`

`=`

`init_stack`

`4`

`;;`

`val p : '_a stack = {ind=0; size=4; elts=[||]}`

# push

`1`

`p`

`;;`

`- : unit = ()`

#for`i`

`=`

`2`

to

`5`

do`push`

`i`

`p`

done`;;`

`Uncaught exception: Stack_full`

# p`;;`

`- : int stack = {ind=4; size=4; elts=[|1; 2; 3; 4|]}`

# pop`p`

`;;`

`- : int = 4`

# pop`p`

`;;`

`- : int = 3`

If we want to prevent raising the exception

#type

'a`stack`

`=`

`{`

mutable`ind`

`:`

int`;`

mutable`size`

`:`

int`;`

mutable`elts`

`:`

'a`array}`

`;;`

#let`init_stack`

`n`

`=`

`{ind`

`=`

`0`

;`size`

`=`

max`n`

`1`

;`elts`

`=`

`[||]}`

`;;`

#let`n_push`

`e`

`p`

`=`

if`p`

`.`

elts

`=`

`[||]`

then

begin

`p`

`.`

elts

`<-`

`Array.create`

`p`

`.`

size`e;`

`p`

`.`

ind

`<-`

`1`

end

else

if`p`

`.`

ind

`>=`

`p`

`.`

size

then

begin

let`nt`

`=`

`2`

`*`

`p`

`.`

size

in

let`nv`

`=`

`Array.create`

`nt`

`e`

in

for`j`

`=`

`0`

to`p`

`.`

size`-`

`1`

do`nv`

`.`

(j)

`<-`

`p`

`.`

elts`.`

(j)

done`;`

`p`

`.`

elts

`<-`

`nv;`

`p`

`.`

size

`<-`

`nt;`

`p`

`.`

ind

`<-`

`p`

`.`

ind

`+`

`1`

end

else

begin

`p`

`.`

elts`.`

(p`.`

ind)

`<-`

`e`

`;`

`p`

`.`

ind

`<-`

`p`

`.`

ind

`+`

`1`

end`;;`

`val n_push : 'a -> 'a stack -> unit = <fun>`

All the same, you have to be careful with data structures which can expand without bound. Here is a small example where the initial stack grows as needed.

#let`p`

`=`

`init_stack`

`4`

`;;`

`val p : '_a stack = {ind=0; size=4; elts=[||]}`

#for`i`

`=`

`1`

to

`5`

do`n_push`

`i`

`p`

done`;;`

`- : unit = ()`

# p`;;`

`- : int stack = {ind=5; size=8; elts=[|1; 2; 3; 4; 5; 5; 5; 5|]}`

# p`.`

stack`;;`

`Characters 0-7:`

`Unbound label stack`

It might also be useful to allow

#type`mat`

`=`

`{`

`n`

`:`

int;`m`

`:`

int;`t`

`:`

`float`

`array`

`array`

`};;`

`type mat = { n: int; m: int; t: float array array }`

#let`create_mat`

`n`

`m`

`=`

`{`

`n`

`=`

n;`m`

`=`

m;`t`

`=`

`Array.create_matrix`

`n`

`m`

`0`

`.`

`0`

`}`

`;;`

`val create_mat : int -> int -> mat = <fun>`

#let`access_mat`

`m`

`i`

`j`

`=`

`m`

`.`

t`.`

(i)`.`

(j)`;;`

`val access_mat : mat -> int -> int -> float = <fun>`

#let`mod_mat`

`m`

`i`

`j`

`e`

`=`

`m`

`.`

t`.`

(i)`.`

(j)

`<-`

`e`

`;;`

`val mod_mat : mat -> int -> int -> float -> unit = <fun>`

#let`a`

`=`

`create_mat`

`3`

`3`

`;;`

`val a : mat = {n=3; m=3; t=[|[|0; 0; 0|]; [|0; 0; 0|]; [|0; 0; 0|]|]}`

# mod_mat`a`

`1`

`1`

`2`

`.`

`0`

;`mod_mat`

`a`

`1`

`2`

`1`

`.`

`0`

;`mod_mat`

`a`

`2`

`1`

`1`

`.`

`0`

`;;`

`- : unit = ()`

# a`;;`

`- : mat = {n=3; m=3; t=[|[|0; 0; 0|]; [|0; 2; 1|]; [|0; 1; 0|]|]}`

The sum of two matrices

#let`add_mat`

`p`

`q`

`=`

if`p`

`.`

n

`=`

`q`

`.`

n

`&&`

`p`

`.`

m

`=`

`q`

`.`

m

then

let`r`

`=`

`create_mat`

`p`

`.`

n`p`

`.`

m

in

for`i`

`=`

`0`

to`p`

`.`

n`-`

`1`

do

for`j`

`=`

`0`

to`p`

`.`

m`-`

`1`

do

`mod_mat`

`r`

`i`

`j`

(p`.`

t`.`

(i)`.`

(j)

`+.`

`q`

`.`

t`.`

(i)`.`

(j))

done

done`;`

`r`

else`failwith`

`"add_mat : dimensions incompatible"`

;;

`val add_mat : mat -> mat -> mat = <fun>`

# add_mat

`a`

`a`

`;;`

`- : mat = {n=3; m=3; t=[|[|0; 0; 0|]; [|0; 4; 2|]; [|0; 2; 0|]|]}`

The product of two matrices

#let`mul_mat`

`p`

`q`

`=`

if`p`

`.`

m

`=`

`q`

`.`

n

then

let`r`

`=`

`create_mat`

`p`

`.`

n`q`

`.`

m

in

for`i`

`=`

`0`

to`p`

`.`

n`-`

`1`

do

for`j`

`=`

`0`

to`q`

`.`

m`-`

`1`

do

let`c`

`=`

`ref`

`0`

`.`

`0`

in

for`k`

`=`

`0`

to`p`

`.`

m`-`

`1`

do

`c`

`:=`

`!`

c

`+.`

(p`.`

t`.`

(i)`.`

(k)

`*.`

`q`

`.`

t`.`

(k)`.`

(j))

done;

`mod_mat`

`r`

`i`

`j`

`!`

c

done

done;

`r`

else`failwith`

`"mul_mat : dimensions incompatible"`

`;;`

`val mul_mat : mat -> mat -> mat = <fun>`

# mul_mat`a`

`a;;`

`- : mat = {n=3; m=3; t=[|[|0; 0; 0|]; [|0; 5; 2|]; [|0; 2; 1|]|]}`