OCaml Planet

November 22, 2014

Andrej Bauer

A HoTT PhD position in Ljubljana

I am looking for a PhD student in mathematics. Full tuition & stipend will be provided for a period of three years, which is also the official length of the programme. The topic of research is somewhat flexible and varies from constructive models of homotopy type theory to development of a programming language for a proof assistant based on dependent type theory, see the short summary of the Effmath project for a more detailed description.

The candidate should have as many of the following desiderata as possible, and at the very least a master’s degree (or an equivalent one):

  1. a master’s degree in mathematics, with good knowledge of computer science
  2. a master’s degree in computer science, with good knowledge of mathematics
  3. experience with functional programming
  4. experience with proof assistants
  5. familiarity with homotopy type theory

The student will officially enrol in October 2014 at the University of Ljubljana. No knowledge of Slovene is required. However, it is possible, and even desirable, to start with the actual work (and stipend) earlier, as soon as in the spring of 2015. The candidates should contact me by email as soon as possible. Please include a short CV and a statement of interest.

by Andrej Bauer at November 22, 2014 12:16 PM

November 20, 2014

Yan Shvartzshnaider

Menhir



This blog post about  -  Menhir.


According to Wikipedia:

A menhir (French, from Middle Breton: men, "stone" and hir, "long"[1]), standing stone, orthostat, or lith is a large upright standing stone.
Coincidently, Menhir, is also the name for LR(1) parser generator for OCaml.
 
I followed the recommendation in the Real World OCaml to use it, rather than ocamlyacc:
"Menhir is an alternative parser generator that is generally superior to the venerable ocamlyacc, which dates back quite a few years. Menhir is mostly compatible with ocamlyacc grammars, and so you can usually just switch to Menhir and expect older code to work (with some minor differences described in the Menhir manual)

I found a few sources online that help you understand Menhir but it took me some time to get my head around it.

This blog (and this post in particular) is mainly for me to record my activities and a way to understand things better. Nevertheless, I hope that by going through and discussing the code I've written, will shorten the learning curve for some of you -  or the very least entertain you :)

On y vas! For my purposes, I started by parsing a simple n-tuple string, for the MoanaML code.
(?x,hasColor,?y,context)
Following the instructions in the Real World OCaml I knew that I had to create two files, a namely, Parser.mly and Lexer.mll

The parser file is used to construct and parse the grammar. You can define tokens and describe their required sequences.

For example, for the Moana tuple, I defined the following tokens:
%token <string> STRING
%token <string> VAR
%token LEFT_BRACE
%token RIGHT_BRACE
%token START
%token END
%token COMMA
%token EOF </string></string>
 I the used them to define the required parsing sequence:
LEFT_BRACE; s = elem; COMMA; p = elem; COMMA; o = elem; COMMA; c  = elem; RIGHT_BRACE 
elem:
 | v = VAR {Variable v}
 | c = STRING {Constant c} 

The elem is there to differentiate constants and variables and consequently pass the parsed value into a relevant type constructor.

You also define the parsing function and its return type
 start < config .tuple > parse
Now once we have the parser, we can move to the lexer file.  Here we define rules using regular expressions in order to match, capture and convert strings into the previously defined tokens.

In my case:

rule lex = parse
  | [' ' '\t' '\n']      { lex lexbuf }
  | newline         { next_line lexbuf; lex lexbuf }
  | ","                 { COMMA }
  | "("                 { LEFT_BRACE }
  | "{"                {START}
  | eof                {EOF }

To do the actual parsing, we use:
Parser.parse_tuple Lexer.lex (Lexing.from_string s)
the Real World OCaml: helps us understand what's happening
[Lexing.from_string] function is used to construct a lexbuf [from a string], which is passed with the lexing function [Lexer.lex] to the [Parser.parse] functions.
That's all, folks!

Pitfalls.

I was expecting Menhir to provide me with nice exceptions to debug my code, as was promised in the Real World OCaml:
The biggest advantage of Menhir is that its error messages are generally more human-comprehensible, ...
but it didn't. At least, I couldn't find the way to invoke it.
In any case, the book does provide you with some code to make the debugging a bit easier.

Anyway, online regular expression editor is your friend - I used http://www.regexr.com. Use it to test your regular expression and adjust the lexer accordingly.

One more thing, the order of your lexer rules matters!

Finally, in addition to the the Real World OCaml book chapter, I also found very useful this example and this Mini Ocaml tutorial.

That's about it, very simple and elegant once you get your head around it.

Disclaimer: As I mentioned in the beginning, I am a newbie, so please let me know if I got some of the stuff wrong or there is a more efficient way of doing things. I am more than happy to hear from you guys!

by Yan (noreply@blogger.com) at November 20, 2014 04:51 PM

November 18, 2014

Daniel Bünzli

Cmdliner 0.9.6

Release of Cmdliner 0.9.6, consult the release notes for details.

November 18, 2014 02:23 PM

Jane Street

How to choose a teaching language

If you were teaching a programming course, what language would you teach it in?

I like this question because it has any number of good answers, each quite different from the other, and each emblematic of a different approach to what programming is about.

The first formal programming class I took was COS 217 at Princeton, taught by the excellent (and at the time, I thought, terrifying) Anne Rogers. The course was (and is) taught in C, and the intellectual approach of the class was to start from the machine. Instead of just learning to program in C, we learned about how the machines we were programming to worked. That was where I first encountered instruction counters, stack frames, registers and the memory hierarchy. It was exhilarating.

Where C encourages you to start with the machine, Scheme wants you to start at the mathematical foundations of computation. You don't need to know what the lambda caluclus is to appreciate Scheme's slim core, and the way in which you can build a rich and vibrant computational world on top of it. That core is expressive enough that it makes it natural to introduce ideas that come up in multiple different languages, including functional and imperative techniques, object orientation, and logic programming.

The classic course in this vein is MIT's 6.001, also known as SICP, The Structure and Interpretation of Computer Programming. Sadly, 6.001 has been retired at MIT, but the book lives on, and is a worthwhile read even if you took your last CS course years ago.

MIT replaced SICP with a course based on Python, and this reflects a broader trend. As was highlighted by an informal study by Philip Guo, lots of schools now teach Python, particularly for early introductory courses. I have mixed feelings about this choice. Python is a wonderfully friendly language, but that friendliness is bundled together with some problems.

This was made apparent to me in part by my experience with students who chose to code in their interviews in Python. In many ways, Python is the ideal interview language, since its concise and readable syntax makes the constraints of coding on the whiteboard more bearable. But what I saw was that students who learn Python often walk away with a rather rough model of the semantics of the language. You might be surprised at what fraction of students who have programmed extensively in Python can't guess how Python lists might be implemented, to say nothing of their ability to explain the semantics of language features like generators or decorators.

This isn't really a knock on Python. After all, there's something great about a tool that lets you get things done without fully understanding how it works. But in different ways, both Scheme and C encourage you to understand what's going on from the ground up, and there's a certain pedagogical power in that. All in, I think Python is a great choice for an early introductory course, particularly one meant for those who aren't going to end up as computer scientists or full-time programmers. But I'd be leery of using it outside of those circumstances.

A development that I'm personally rather encouraged by is the emergence of statically typed functional languages, ML in particular, as teaching tools. Over the last few years, I've had the pleasure of visiting and lecturing at a number of schools that teach using OCaml or SML, including Brown, Cornell, Penn, Princeton, CMU and Harvard.

ML has gained ground for good reasons. First, it shares much of Scheme's elegant intellectual foundations, even though its core isn't quite as charmingly minimalistic as Scheme's. But ML has a wider range than Scheme because it allows you to show students the role of types in programming. Despite that greater range, OCaml and SML are relatively simple languages, which matters even more for teaching than it does for everyday use.

The only choice I've seen a lot of that I can't reconcile myself to is Java. Java is of course a widely used industrial language, but that doesn't mean it's a good teaching language. In my view, a key requirement for a teaching language is simplicity, and all the other choices I mentioned are simple in one way or another: C is a minimal layer on top of the machine; Scheme and ML are based on simple mathematical models of computation; and Python is a language that people find simple to use.

Java isn't simple in any of these ways. It's not particularly easy to get started with, as indicated by all the things you need to tell students to ignore rather than understand. (Yeah, public static void main, I'm looking at you!) Nor does it have a simple and transparent execution model like C. And an elegant computational core calculus like the one at the heart of Scheme and ML is nowhere in sight. The only real advantage I see for Java is vocational, and that doesn't seem to me like argument enough.

The thing to consider when you're picking a language to teach is that you're not just picking a bit of infrastructure for your students to program with during the course. You're picking an intellectual frame through which they will see all the lessons you teach them. And you should pick that frame with care.

by Yaron Minsky at November 18, 2014 12:05 AM

November 15, 2014

Mads Hartman

ocamldebug

When I first read about the time-travel feature of the ocaml debugger I was very intrigued but never got around to trying it out in practice at work. This weekend I decided to give it a go.

I wanted to try it out on a simple but non-trivial program (in terms of setup, i.e. a program that requires opam packages to compile) so I used the hello world example of the ocaml-cohttp library.

1 Configuration

Before the ocamldebugger can work with your programs they need to be compiled with the -g flag enabled. This is also required for any libraries that you use. You can configure the ocamlc parameters that opam uses by setting OCAMLPARAM; in this case you want to set it to _,g. You will want to run opam reinstall on any package you have previously installed to make sure they get recompiled.

The second thing you need to do is tell ocamldebug where to look for your compiled files. Unfortunately this is not as easy as it is with utop. Luckily I came across this stack overflow thread which explains how to do it. I ended up using a slightly different approach as you can't pass arguments to ocamldebug when running it from within Emacs (at least I couldn't get it to work). I decided to write the results of ocamlfind query -recursive core async cohttp cohttp.async into a file named .ocamldebug and prefix each line with directory. After starting the debugger in Emacs you then need to run source <PATH> to configure it.

2 Using the debugger

Starting the debugger from within Emacs is just a matter of running M-x ocamldebug and point it to the executable you want to debug.

You start the program by writing run in the ocamldebug buffer. You set break-points in your code using C-x C-a C-b and step through the code use C-c C-s. You can inspect values using C-x C-a C-p. For more information read this chapter of the OCaml Users Guide.

3 Shortcomings

Unfortunately I found a couple of shortcomings when I played around with the debugger for a bit.

3.1 No support for -pack'ed compilation units

Once you start setting some breakpoints and step through the code you're very likely to get an error like the following.

(ocd) step
Time: 1084742 - pc: 4416712 - module Cohttp.Request
No source file for Cohttp.Request.

This error had me puzzled for a bit as I thought I had already told ocamldebug where to look for my opam packages. I joined the #ocaml IRC channel and whitequark was able to come up with a potential explanation. It seems that ocamldebug doesn't support compilation units that contain submodules that have been added using -pack and -for-pack. Search for -pack in this section for the OCaml Users Guide for more information.

3.2 No arbitrary OCaml code execution

Once you hit a breakpoint it's possible to inspect the values of the variables in the current scope. This is great, but it would have been even better if you could execute arbitrary OCaml code in the current scope. This doesn't seem to be possible. To be fair this might be better classified as an awesome feature rather than a shortcoming.

November 15, 2014 09:00 PM

November 13, 2014

Shayne Fletcher

Dimensional Analysis in OCaml

Dimensional analysis in OCaml

In 1994, Barton and Nackman in their book 'Scientific Engineering in C++' [1] demonstrated how one could encode the rules of dimensional analysis into the C++ type system enabling compile-time checking (no run-time cost) of the plausibility (at least up to the dimensional correctness) of computations.

In 2004, Abrahams & Gurtovy in 'C++ Template Metaprogramming' [2] showed the Barton Nackman technique to be elegantly implementable using compile time type sequences encoding integer constants. The key properties of the technique are:

  • Encoding of integers as types;
  • Compile time manipulation of sequences of these integer encodings to deduce/produce new derived types.

For a good while there it escaped me how to approach this problem in OCaml and it bothered me somewhat. I turned to the caml-list for guidance and I'm happy to say some notable 'Camlers' there helped me out (thank-you Octachron, Mario Alvarez Picallo, Thomas Gazagnaire, Roberto Di Cosmo and David Mentre)!

The key idea in the solution to follow is the encoding of integers into the type-system as differences between two Peano numbers. The details of the approach are presented in the excellent paper "Many Holes in Hindley-Milner" by Sam Lindley of the University of Edinburgh.

Credit for the code that follows goes to Mario Alvarez Picallo. I generalized Mario's program to the extent that I could do the "force on a laptop" exercise (as presented in the online Boost.MPL tutorial).

The module interface is where all the work is - getting the "type-math" correct.


module type S = sig

type +'a s = 'a * 'a
type (+'a,+'b,+'c,+'d,+'e,+'f,+'g,+'h,+'i,+'j,+'k,+'l,+'m,+'n) t

(*Base dimensions*)

val mass :
float -> ('a,'a s,'b,'b,'c,'c,'d,'d,'e,'e,'f,'f,'g,'g) t
val length :
float -> ('a,'a,'b,'b s,'c,'c,'d,'d,'e,'e,'f,'f,'g,'g) t
val time :
float -> ('a,'a,'b,'b,'c,'c s,'d,'d,'e,'e,'f,'f,'g,'g) t
val charge :
float -> ('a,'a,'b,'b,'c,'c,'d,'d s,'e,'e,'f,'f,'g,'g) t
val temperature :
float -> ('a,'a,'b,'b,'c,'c,'d,'d,'e,'e s,'f,'f,'g,'g) t
val intensity :
float -> ('a,'a,'b,'b,'c,'c,'d,'d,'e,'e,'f,'f s,'g,'g) t
val angle :
float -> ('a,'a,'b,'b,'c,'c,'d,'d,'e,'e,'f,'f,'g,'g s) t

(*Composite dimensions*)

val velocity :
float -> ('a,'a,'b,'b s,'c s,'c,'d,'d,'e,'e,'f,'f,'g,'g) t
val acceleration :
float -> ('a,'a,'b,'b s,'c s s,'c,'d,'d,'e,'e,'f,'f,'g,'g) t
val momentum :
float -> ('a,'a s,'b,'b s,'c s,'c,'d,'d,'e,'e,'f,'f,'g,'g) t
val force :
float -> ('a,'a s,'b,'b s,'c s s,'c,'d,'d,'e,'e,'f,'f,'g,'g) t

(*Arithmetic*)

val ( + ) :
('a,'b,'c,'d,'e,'f,'g,'h,'i,'j,'k,'l,'m,'n) t ->
('a,'b,'c,'d,'e,'f,'g,'h,'i,'j,'k,'l,'m,'n) t ->
('a,'b,'c,'d,'e,'f,'g,'h,'i,'j,'k,'l,'m,'n) t
val ( - ) :
('a,'b,'c,'d,'e,'f,'g,'h,'i,'j,'k,'l,'m,'n) t ->
('a,'b,'c,'d,'e,'f,'g,'h,'i,'j,'k,'l,'m,'n) t ->
('a,'b,'c,'d,'e,'f,'g,'h,'i,'j,'k,'l,'m,'n) t
val ( * ) :
('a0,'b0,'c0,'d0,'e0,'f0,'g0,'h0,'i0,'j0,'k0,'l0,'m0,'n0) t ->
('b0,'b1,'d0,'d1,'f0,'f1,'g0,'h1,'i0,'j1,'k0,'l1,'m0,'n1) t ->
('a0,'b1,'c0,'d1,'e0,'f1,'g0,'h1,'i0,'j1,'k0,'l1,'m0,'n1) t
val ( / ) :
('a0,'b0,'c0,'d0,'e0,'f0,'g0,'h0,'i0,'j0,'k0,'l0,'m0,'n0) t ->
('a1,'b0,'c1,'d0,'e1,'f0,'g1,'h0,'i1,'j0,'k1,'l0,'m1,'n0) t ->
('a0,'a1,'c0,'c1,'e0,'e1,'g0,'g1,'i0,'i1,'k0,'k1,'m0,'m1) t

(*Conversion to float*)

val value : ('a,'b,'c,'d,'e,'f,'g,'h,'i,'j,'k,'l,'m,'n) t -> float
end

That's the hard part, the module implementation itself is trivial.


module Dim : S = struct

type +'a s = 'a * 'a
type (+'a,+'b,+'c,+'d,+'e,+'f,+'g,+'h,+'i,+'j,+'k,+'l,+'m,+'n) t = float

let mass x = x
let length x = x
let time x = x
let charge x = x
let temperature x = x
let intensity x = x
let angle x = x

let velocity x = x
let acceleration x = x
let momentum x = x
let force x = x

let ( + ) = ( +. )
let ( - ) = ( -. )
let ( * ) = ( *. )
let ( / ) = ( /. )

let value x = x

end

And the motivating "force on a laptop" calculation? Well in the top-level it proceeds like this.


# open Dim ;;
# let m = mass 5.0 ;;
val m : ('a,'a Dim.s,'b,'b,'c,'c,'d,'d,'e,'e,'f,'f,'g,'g) Dim.t =
<abstr>
# let a = acceleration 9.8 ;;
val a :
('a,'a,'b,'b Dim.s,'c Dim.s Dim.s,'c,'d,'d,'e,'e,'f,'f,'g,'g)
Dim.t = <abstr>
# let f = m * a ;;
val f :
('a,'a Dim.s,'b,'b Dim.s,'c Dim.s Dim.s,'c,'d,'d,'e,'e,'f,'f,'g,'g)
Dim.t = <abstr>
Now to verify the result.

# let m2 = f / a ;;
val m2 :
('a,'a Dim.s,'b,'b,'c Dim.s Dim.s,'c Dim.s Dim.s,'d,'d,'e,'e,'f,'f,'g,'g)
Dim.t = <abstr>
If we got things right, then we'd expect that the difference m2 - m be close to zero (within rounding error).

# value (m2 - m) ;;
- : float = 0.
Indeed it is as we hoped.

The key test though is this, if we had written a/f instead of f/a we want that there be type-check failure preventing the mistake from propagating through the program.


# let m2 = a / f (*oops*) ;;
val m2 :
('a Dim.s,'a,'b,'b,'c Dim.s Dim.s,'c Dim.s Dim.s,'d,'d,'e,'e,'f,'f,'g,'g)
Dim.t = <abstr>
# m2 - m ;;
Characters 5-6:
m2 - m ;;
^
Error:
This expression has type
('a Dim.s,'a Dim.s Dim.s,'b,'b,'c,'c,'d,'d,'e,'e,'f,'f,'g,'g) Dim.t
but an expression was expected of type
('a Dim.s,'a,'h,'h,'i Dim.s Dim.s,'i Dim.s Dim.s,'j,'j,'k,'k,'l,'l,'m,'m) Dim.t
The type variable 'a occurs inside 'a Dim.s * 'a Dim.s
And there it is. Happy days!

[1] John J. Barton and Lee R. Nackman. Scientific and Engineering C++: an Introduction with Advanced Techniques and Examples. Reading, MA: Addison Wesley. ISBN 0-201-53393-6. 1994.

[2] David Abrahams and Aleksey Gurtovy C++ Template Metaprogramming: Concepts, Tools, and Techniques from Boost and Beyond (C++ in Depth Series), Addison-Wesley Professional. ISBN:0321227255. 2004.

by Shayne Fletcher (noreply@blogger.com) at November 13, 2014 07:38 PM

Mads Hartman

OCaml Briefly

this document gives you a brief tour of OCaml. It covers a rather small selection of features; the selection has been based on what features I personally think represent OCaml the best.

This document does very little to explain use-cases for the selected features but rather focuses on syntax. For a more in-depth coverage of all of these features I recommend reading the OCaml Document and User's Manual and Real World OCaml.

For each feature there is a small explanation of the syntax, some examples, and links for further reading. As such this document is ideal for someone who wants to get a taste of the features of OCaml or who want to learn more about a specific feature.

If you have any comments please reach out to me at mads379@gmail.com or @mads_hartmann on twitter.

If you want to play around with the code I recommend using this online REPL.

Note: This is still a work in progress. I haven't yet covered the following: pattern matching, modules, functors, exceptions, Abstract Data Types, Generalized Algebraic Datatypes, and much more.

1 Lists, Arrays, and Tuples

A List is constructed using square brackets where the elements are separated by semi-colons:

[ 1 ; 2; 3 ];;
- : int list = [1; 2; 3]

An Array is constructed using square brackets with bars where the elements are separated by semi-colons:

[| 1 ; 2; 3 |];;
- : int array = [|1; 2; 3|]

Tuples are constructed using parens and the elements are separated using commas:

( "foo", "bar", "foobar" )
- : string * string * string = ("foo", "bar", "foobar")

2 Let-bindings

A let-binding associates an identifier with a value. It is introduced using the following syntax let <identifier> = <expression> in <expression>.

let hi = "hi " in
let there = "there!" in
hi ^ there;;
hi there!

The ^ is a function that concatenates two strings. The ^ function is used as an infix operator in the example above but it could just as easily have been invoked in a prefix manner as shown below.

(^) "Hi " "there";;
Hi there

Let-bindings are also used to declare functions. More on that in the next section.

3 Functions

As was shown in the previous section you invoke a function by adding the arguments after the function name separated by whitespace.

min 42 10;;
10

It might take some time to get used to separating function arguments with whitespace rather than commas as you do in other programming languages. In another language the above example might look like this:

min(10,24);;
- : int * int -> int * int = <fun>

However, in OCaml this will partially apply the function min with one argument, the tuple (10, 24). Partial application is another nice feature of OCaml that allows you to supply N arguments to a function of arity X and get a function of arity X-N in return. This is possible as all functions in OCaml are curried.

let at_least_42 = max 42 in
at_least_42 22;;
42

3.1 Defining functions

A function is defined using the following syntax let <name> <arg1> <arg2> = <expression> in <expression>, that is, the function name followed by it's arguments separated by whitespace.

The following is a function that takes one argument x (which is inferred to be an integer) and returns the square value of that integer.

let square x = x * x;;
val square : int -> int = <fun>

You can use the fun keyword to introduce a lambda, it has the following syntax fun <arg1> <arg2> -> <expression>. So the example above is equivalent to this:

let square = fun x -> x * x;;
val square : int -> int = <fun>

As mentioned earlier some functions can be used as infix operators. A function can be used as in infix operator if one of the following names are used ! $ % & * + - . / : < = > ? @ ^ | ~. Read more about infix and prefix functions in this section of Real World OCaml.

If your function only takes one argument and you want to pattern match on it you can use the function keyword (please ignore this horribly inefficient implementation I'm about to show you):

let rec sum = function
  | x :: xs -> x + (sum xs)
  | [] -> 0
in sum [1;2;3;4;5;1;2];;
18

More on pattern matching later. The previous example also shows that if you want to define a recursive function in OCaml you have to use the rec keyword.

3.1.1 Labeled arguments

By prefixing an argument with ~ you can give it a label which makes the code easier to read and makes the order of the arguments irrelevant.

let welcome ~greeting ~name = Printf.printf "%s %s\n" greeting name in
welcome ~name:"reader" ~greeting:"Hi"
Hi reader
- : unit = ()

3.1.2 Optional arguments

By prefixing an argument with ? you can make it optional. The value of optional arguments are represented using the Option type.

let welcome ?greeting_opt name =
  let greeting = match greeting_opt with
    | Some greeting -> greeting
    | None -> "Hi"
  in
  Printf.printf "%s %s\n" greeting name
in
welcome ~greeting_opt:"Hey" "reader" ;
welcome ?greeting_opt:None "reader"
Hey reader
Hi reader
- : unit = ()

3.1.3 Default argument

For optional arguments you can provide a default value. Thus the previous example could also have been written as such:

let welcome ?(greeting="Hi") name =
  Printf.printf "%s %s\n" greeting name
in
welcome ~greeting:"Hey" "reader" ;
welcome "reader"
Hey reader
Hi reader
- : unit = ()

4 Records

Records are used to store a collection of values together as a single value. The example below defines a record named person with two components.

type person = {
  name: string;
  age: int;
} ;;
let p = { name = "Mads" ; age = 25 } in
Printf.printf "%s is %d years old" p.name p.age
Mads is 25 years old- : unit = ()

Records can be parameterized using a polymorphic type.

type 'a ranked = {
  item: 'a;
  rank: int;
};;
let item = { item = Some 42 ; rank = 1 }
val item : int option ranked = {item = Some 42; rank = 1}

There is a lot more to be said of records. See this this section of Real World OCaml and this section of the OCaml Users Guide.

5 Variants

Variants, also known as algebraic data types, are commonly used to define recursive data structures. Just like records they can be parameterized using a polymorphic type as shown in the example below where a variant is used to represent a binary tree.

type 'a tree =
  | Leaf of 'a
  | Node of 'a tree * 'a * 'a tree;;
Node ((Leaf "foo"), "bar", (Leaf "foobar"));;
- : string tree = Node (Leaf "foo", "bar", Leaf "foobar")

The type tree has two constructors: Leaf and Node. The example below shows one way to compute the height of such a tree:

let rec depth = function
  | Leaf _ -> 1
  | Node (left, _ ,right) -> 1 + max (depth left) (depth right)
in
let tree =
  Node ((Leaf 1), 2, (Node ((Leaf 3), 4, (Node ((Leaf 5), 6, (Leaf 6))))))
in
depth tree;;
4

The example above uses the function keyword to define a function that takes a single argument that is pattern matched on.

Variants are one of the most useful features of OCaml so it's well worth spending some more time studying them. See this section of Real World OCaml for information on use-cases and best-practices.

5.1 Polymorphic Variants

OCaml also has another type of variants that they call polymorphic variants. When using polymorphic variants you do not need to define the constructors prior to using them - you can think of them as an ad-hoc version of the regular variants.

let length_of_title book_title =
  match String.length book_title with
  | length when length <= 5  -> `Short
  | length when length <= 10 -> `Medium
  | _  -> `Long
in
length_of_title "The Hitchhiker's Guide to the Galaxy"
- : [> `Long | `Medium | `Short ] = `Long

Once again this feature is thoroughly covered in this section of Real World OCaml.

5.2 Extensible Variants

As the name suggests extensible variants are variants that can be extended with new constructors.

This is a new feature that was introduced in OCaml 4.02 and as such I haven't yet used these in my own code so I will stick to the examples shown in the OCaml Users Manual.

type attr = .. ;;
type attr += Str of string ;;
type attr +=
  | Int of int
  | Float of float ;;
type attr += Int of int | Float of float

For more information read this section of the OCaml Users Manual. This features was released after Real World Ocaml and as such it isn't covered in the book unfortunately. I look forward to then next revision.

November 13, 2014 02:00 PM

Yan Shvartzshnaider

Ocaml teaching resources

[Update: The Ocaml teaching resource page is now live]

I am helping the folks behind OCaml.org with setting up a page that will useful resources for educators that want to teach OCaml to masses.

We are looking to include helpful guides on how to setup a development environment, provide links to useful VMs as well as list some tips for complete beginners. There is a lot of material on the web, however it is scattered all over the places and sometimes hard to find. We will try to find the best of the lot and have them referenced in one place.

Watch this space...I really meant this space.

We are also listing all the universities where OCaml is being taught.

Let us know if we missed any.

It is great to see them on the Google maps as well :)

<iframe height="480" src="https://www.google.com/maps/d/embed?mid=zk8_K4G_usic.kkzYvEvqV44Q" width="640"></iframe>

by Yan (noreply@blogger.com) at November 13, 2014 09:29 AM