Harvard is again teaching OCaml to its first-year students, and Greg Morrissett again this year invited me to give a guest lecture. I gave a version of the Effective ML talk that I gave last year to the same class.
OCaml seems to be getting some real currency as a teaching language in the US. Harvard, Penn and Cornell are all teaching it to their undergraduates as part of the standard curriculum. And SML has of course been taught for a long time at CMU, and Brown and Northeastern teach Scheme/Racket.
As a side note, the class has grown considerably, with over 200 students enrolled in cs51. Apparently, a lot of the growth is the result of people seeing “The Social Network” and getting inspired to go study Computer Science….
When I gave this talk last, there were some requests for the code snippets, so I’ve included the (updated) snippets below. In order to understand the context of these, watch last year’s talk!
Use uniform interfaces
module type Comparable = sig
type t
val compare : t -> t -> [ `Lt | `Eq | `Gt ]
val ( >= ) : t -> t -> bool
val ( <= ) : t -> t -> bool
val ( = ) : t -> t -> bool
val ( > ) : t -> t -> bool
val ( < ) : t -> t -> bool
val ( <> ) : t -> t -> bool
val min : t -> t -> t
val max : t -> t -> t
module Map : Core_map.S with type key = t
module Set : Core_set.S with type elt = t
end
module Char : sig
type t
include Comparable with type t := t
include Stringable with type t := t
include Hashable with type t := t
end
Make illegal states unrepresentable
Before:
type connection_state =
| Connecting
| Connected
| Disconnected
type connection_info = {
state: connection_state;
server: Inet_addr.t;
last_ping_time: Time.t option;
last_ping_id: int option;
session_id: string option;
when_initiated: Time.t option;
when_disconnected: Time.t option;
}
After:
type connecting = { when_initiated: Time.t; }
type connected = { last_ping : (Time.t * int) option;
session_id: string; }
type disconnected = { when_disconnected: Time.t; }
type connection_state =
| Connecting of connecting
| Connected of connected
| Disconnected of disconnected
type connection_info = {
state : connection_state;
server: Inet_addr.t;
}
Code for exhaustiveness
type message = | Order of Order.t
| Cancel of Order_id.t
| Exec of Execution.t
let position_change m =
match m with
| Exec e ->
let dir = Execution.dir e in
Dir.sign dir * Execution.quantity e
| _ -> 0
Open few modules
Before:
open Core.Std
open Command
open Flag
type config = { exit_code: int;
message: string option; }
let command =
let default_config = { exit_code = 0; message = None } in
let flags =
[ int "-r" (fun cfg v -> { cfg with exit_code = v });
string "-m" (fun cfg v -> { cfg with message = v });
]
in
let main cfg =
Option.iter cfg.message (fun x -> eprintf "%s\n" x);
cfg.exit_code
in
create ~summary:"does nothing, successfully"
~default_config ~flags ~main
let () = run command
After:
open Core.Std
type config = { exit_code: int;
message: string option; }
let command =
let default_config = { exit_code = 0; message = None } in
let flags =
let module F = Command.Flag in
[ F.int "-r" (fun cfg v -> { cfg with exit_code = v });
F.string "-m" (fun cfg v -> { cfg with message = v });
]
in
let main cfg =
Option.iter cfg.message (fun x -> eprintf "%s\n" x);
cfg.exit_code
in
Command.create ~summary:"does nothing, successfully"
~default_config ~flags ~main
let () = Command.run command
Make common errors obvious
module List : sig
type 'a t
....
val find : 'a t -> ('a -> bool) -> 'a option
val find_exn : 'a t -> ('a -> bool) -> 'a
val hd : 'a t -> 'a option
val hd_exn : 'a t -> 'a
val reduce : 'a t -> ('a -> 'a -> 'a) -> 'a option
val reduce_exn : 'a t -> ('a -> 'a -> 'a) -> 'a
val fold : 'a t -> init : 'b -> ('a -> 'b -> 'b) -> 'b
.....
end