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

  1. module type Comparable = sig
  2. type t
  3.  
  4. val compare : t -> t -> [ `Lt |`Eq | `Gt ]
  5.  
  6. val ( >= ) : t -> t -> bool
  7. val ( <= ) : t -> t -> bool
  8. val ( = ) : t -> t -> bool
  9. val ( > ) : t -> t -> bool
  10. val ( < ) : t -> t -> bool
  11. val ( <> ) : t -> t -> bool
  12. val min : t -> t -> t
  13. val max : t -> t -> t
  14.  
  15. module Map : Core_map.S with type key = t
  16. module Set : Core_set.S with type elt = t
  17. end
  1. module Char : sig
  2. type t
  3. include Comparable with type t := t
  4. include Stringable with type t := t
  5. include Hashable with type t := t
  6. end

Make illegal states unrepresentable

Before:

  1. type connection_state =
  2. | Connecting
  3. | Connected
  4. | Disconnected
  5.  
  6. type connection_info = {
  7. state: connection_state;
  8. server: Inet_addr.t;
  9. last_ping_time: Time.t option;
  10. last_ping_id: int option;
  11. session_id: string option;
  12. when_initiated: Time.t option;
  13. when_disconnected: Time.t option;
  14. }

After:

  1. type connecting = { when_initiated: Time.t; }
  2. type connected = { last_ping : (Time.t * int) option;
  3. session_id: string; }
  4. type disconnected = { when_disconnected: Time.t; }
  5.  
  6. type connection_state =
  7. | Connecting of connecting
  8. | Connected of connected
  9. | Disconnected of disconnected
  10.  
  11. type connection_info = {
  12. state : connection_state;
  13. server: Inet_addr.t;
  14. }

Code for exhaustiveness

  1. type message = | Order of Order.t
  2. | Cancel of Order_id.t
  3. | Exec of Execution.t
  4.  
  5. let position_change m =
  6. match m with
  7. | Exec e ->
  8. let dir = Execution.dir e in
  9. Dir.sign dir * Execution.quantity e
  10. | _ -> 0

Open few modules

Before:

  1. open Core.Std
  2. open Command
  3. open Flag
  4.  
  5. type config = { exit_code: int;
  6. message: string option; }
  7.  
  8.  
  9. let command =
  10. let default_config = { exit_code = 0; message = None } in
  11. let flags =
  12. [ int "-r" (fun cfg v -> { cfg with exit_code = v });
  13. string "-m" (fun cfg v -> { cfg with message = v });
  14. ]
  15. in
  16. let main cfg =
  17. Option.iter cfg.message (fun x -> eprintf "%s\n" x);
  18. cfg.exit_code
  19. in
  20. create ~summary:"does nothing, successfully"
  21. ~default_config ~flags ~main
  22.  
  23. let () = run command

After:

  1. open Core.Std
  2.  
  3. type config = { exit_code: int;
  4. message: string option; }
  5.  
  6.  
  7. let command =
  8. let default_config = { exit_code = 0; message = None } in
  9. let flags =
  10. let module F = Command.Flag in
  11. [ F.int "-r" (fun cfg v -> { cfg with exit_code = v });
  12. F.string "-m" (fun cfg v -> { cfg with message = v });
  13. ]
  14. in
  15. let main cfg =
  16. Option.iter cfg.message (fun x -> eprintf "%s\n" x);
  17. cfg.exit_code
  18. in
  19. Command.create ~summary:"does nothing, successfully"
  20. ~default_config ~flags ~main
  21.  
  22. let () = Command.run command

Make common errors obvious

  1. module List : sig
  2. type 'a t
  3.  
  4. ....
  5.  
  6. val find : 'a t -> ('a -> bool) -> 'a option
  7. val find_exn : 'a t -> ('a -> bool) -> 'a
  8.  
  9. val hd : 'a t -> 'a option
  10. val hd_exn : 'a t -> 'a
  11.  
  12. val reduce : 'a t -> ('a -> 'a -> 'a) -> 'a option
  13. val reduce_exn : 'a t -> ('a -> 'a -> 'a) -> 'a
  14.  
  15. val fold : 'a t -> init : 'b -> ('a -> 'b -> 'b) -> 'b
  16.  
  17. .....
  18.  
  19. end