
-----------------------------------
wtd
Fri Jul 23, 2004 9:20 pm

[O'Caml-tut] Imperative Syntax
-----------------------------------
Along with its support for functiuonal programming techniques, O'Caml also offers syntax more familiar to those who have coded in imperative programming languages.

If ... Else

if 1 = 0 then "They match!" else "They don't match, of course."

This is considered by O'Caml to be a single expression, though in it we see three expressions.

1 = 0
This expression tests to see if 1 equals 0.
"They match!"
Just a literal value... a string.
"They don't match, of course."
Again, a literal value.

Any single expression can follow "then".  Thus, to get "else if" is as simple as:

if 1 = 0 then "foo" else if 1 = 2 then "bar" else "baz"

If any of the string literals used in the above code needs to be multiple expressions, then "begin" and "end" can be used to group multiple expressions into a single expression.

As an example, the below checs to see if a user input the correct password.  It's extremely simple.  Prompt and read a password once.  If the input if correct, output that input.  If it's not, prompt again and return the new input.

let password = "God" and 
user_input = print_string "input a password: "; read_line () in
   if password = user_input then user_input
   else begin
      print_endline "bad_input... try again";
      read_line ()
   end

Loops

O'Caml contains both a while loop and a for loop.  Both are quite versatile.  They evaluate a sequence of expressions until a condition becomes false.  The only real requirement is that the seqence of expressions evaluates to "unit" (O'Caml's equivalent to "void").

I'll start out with something as simple as a count from 0 to 10.

for i = 0 to 10 do print_int i done

Or we could go from 10 to 0.

for i = 10 downto 0 do print_int i done

And a while loop can do either, when combined with a reference.  A reference is essential in this case because with normal O'Caml behavior, a name bound to a value can only be rebound to a new value, and rebinding within the loop wouldn't have any effect the next time around.

The ! and := are the only strange looking bits of code in this case.  ! dereferences a reference, and := assigns to a reference.

let i = ref 0 in
   while !i  []

Of course, it's equally easy to create our own exceptions.

exception Somethings_wrong

This is about as simple an exception as anyone could hope for.  Raising it is as smple as:

raise Somethings_wrong

And catching it is as simple as:

try raise Somethings_wrong with Somethings_wrong -> "Error occurred"

Of course, this doesn't provide any information about what went wrong.  To have an argument for an exception that can be set when the exception is raised, we simply change the above to:

exception Somethings_wrong of string

try raise (Somethings_wrong "hello world!") with Somethings_wrong err_msg -> "Error occurred: " ^ err_msg

Now, what if we want to handle different error messages differently?

try raise (Somethings_wrong "hello world!") with 
   Somethings_wrong "Foo!" -> "Error occurred, but ignore it..."
   | Somethings_wrong err_msg -> "Error occurred, somebody's playing games with us..."
   | Somethings_wrong err_msg -> "Error occurred: " ^ err_msg
