kuniga.me > NP-Incompleteness > 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.
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:
Statements
Statements boundaries are defined by ;;
. Example:
This let us define multi-line expressions,
Comments
Load code from file
It can become tedious to edit functions in the CLI. It’s possible to execute the contents of a file:
Basic Types
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:
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 (+.
)
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:
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 int
s.
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.
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.