Exploring OCaml

kuniga.me > NP-Incompleteness > Exploring OCaml

# Exploring OCaml

27 Jun 2016

I’ve been learning the basics of OCaml in order to be able to follow the examples from Purely Functional Data Structures, from Chris Okasaki.

My background is that I have zero knowledge about OCaml, but having studied a bit of Haskell, I’m familiar with the main concepts in functional programming, so I’ll try to focus on syntax + difference between the two languages. I’ll probably skim through concepts from functional programming I’ve already covered previously on past Haskell posts.

### Setup

I used to skip the setup from posts, but it might be useful to someone, especially with a similar environment, so I decided to include it here. This setup assumes MacOS and emacs.

Installing

Easily available on Brew:

For other OS’es: https://ocaml.org/docs/install.html

Emacs syntax highlighting

Looks like tuareg is a popular mode for developing OCaml in emacs:

At the configuration file (~/.emacs.d/init.el) we can add:

OCaml CLI

Typing ocaml in the terminal will bring up the CLI, but it’s not very interactive, not having a good way to go back previous command or edit strings in the middle. I’ve learned about this command line called rlwrap that implements this functionality. We can easily install it on mac:

And invoke ocaml like this:

We can also add a simple alias to have these features as default:

### Language Basics

Statements

Statements boundaries are defined by ;;. Example:

This let us define multi-line expressions,

It can become tedious to edit functions in the CLI. It’s possible to execute the contents of a file:

Basic Types

• int - 31 or 63-bits, depending on the platform one of the bits is used for internal memory management

When writing literal number values, the underscore character is ignored (as long as it’s not the leading character). For example:

This can be useful to define large numbers in a more user friendly way:

• float - IEEE double-precision floating point

OCaml doesn’t do explicit casts, especially between ints and floats. We have to cast using functions like int_of_float or float_of_int. Examples:

Note that the sum operator for floats has an extra . character (+.)

• bool - true/false
• char - 8-bit ascii character
• string - more than a list of char, efficient internal representation

Variables

We can define variables by the use of let

This looks like imperative code at the first glance, but it’s slightly different. let <expr1> in <expr2>. The expr1 is only made available inside the scope of expr2. For example:

Here the variable a was defined only for the expression:

When we terminated it with ;; , a was out of scope. We can also bind multiple variables in the same expression, for example:

### Functions

Defining Functions

Example: A simple sum function

Note how the type signature syntax is very similar to Haskell.

Explicit function type signature

Sometimes to avoid ambiguity, we might want to provide the types for the inputs/outputs of the function. For example, we might want to define a sum function only intended to be used by ints.

Lambda functions

Denoted by the use of the fun construct, it’s useful for passing simple functions as parameter (for example to a map over lists).

Recursive functions

A function must be explicitly marked as recursive by add a rec, according to [2], due to technical reasons - mainly related to type inference.

Example: Computing the factorial of a natural number n:

Matching patterns

Similar to Haskell, Ocaml has pattern match which we can use to decide which body of function to apply. For example, to invert a list we can do:

The _ operator indicates all the non-matched cases. For example, we could rewrite the reverseList function as

Labeled arguments

We can prefix a function parameter with ~ to indicate it’s a labeled (named) argument. Example:

Note how the variable name shows up in the function’s type signature. It’s important because we may pass a function with labeled arguments to another function and it may make use of this fact (it’s also useful for documentation).

If the variable name matches the named parameter, we don’t need to repeat ourselves:

We can also apply currying using named arguments. For example, if we want generate a new function with the value b “bound”, we can do

When currying, positional parameters (i.e. non-labeled arguments) are always bound before the labeled ones. For example:

Optional parameters

Optional parameters are prefixed with ? like sep in the example below:

The value coming from an optional parameter is either None or Some x. An optional parameter is also a labeled parameter.

In the example above, we use pattern matching to provide a default value to sep. There’s a shorter syntax for this:

By providing a default value, the value in the sep variable won’t be either None/Some, but the actual type expected, in this case a string.

It can be tricky to apply curry in the presence of optional arguments. [2] discusses in detail the heuristics applied by the compiler in different scenarios.

### Conclusion

In this post we covered the very minimum to get our hands dirty with some OCaml code and learn the basic syntax. I don’t plan to study [2] for now. I’m mostly interested in learning enough to follow along Purely Functional Data Structures.

Some first impressions: the ocaml CLI is pretty limited, but thanks to rlwrap it becomes manageable. Haskell is more elegant, Ocaml is more practical.

For the next post in the series I plan to study the most basic and simple data structure in functional programming: lists.

### References

• [1] OCaml.org - The Basics
• [2] Real World OCaml - Chapter 2. Variables and Functions