You should read this post first.
Last week or so I thought I would start to learn Perl or Lua, but I discovered OCaml…and then my focus instantly shifted into it. I’m not really sure what I’ll do about the language, but for now I’m studying it a little bit, so I’ll post here a few notes about it.
Note: this post is likely to be updated as I progress through the language; alternatively, a new post might be created, or I can abandon this thing altogether (yeah, this happens).
- To get an interpreter: ocaml
- Now enter valid OCaml expressions, and finish them with ;;
- You can enter more than one expression at a time, e.g.
let x = 1 let y = 2 ;;
- Equivalently, you can write a script.ml file and enter these same commands, then enter into the interpreter and type:
- Alternatively, you can compile this script with ocamlc. This will create three files: an executable (a.out by default), a.cmi (interface) and a.cmo (object file).
- To run an OCaml executable, use ocamlrun.
- Up to here, this is very similar to haskell: ghc, ghci, and runhaskell.
- Pattern matching is very easy overall (as with haskell)
let isvowel c = match c with 'a' | 'e' | 'i' | 'o' | 'u' -> true | _ -> false;;
- However, I find P.M. more explicit with OCaml. Haskell uses function overloading to implement pattern matching (at least in the syntax level), while OCaml uses a switch-like statement to do that. Well, actually haskell desugars function overloading to a ‘case’ expression behind the scenes, which is very similar to OCaml’s match, but hey…it is just slightly easier to read the OCaml syntax.
- You can use _ to match anything.
- You can also use _ to ignore what is not relevant to you in a match, e.g. when matching tuples:
let fst (x, _) = x;; let snd (_, y) = y;;
- You can match character ranges, e.g. ‘A’..’Z’.
- Two bindings are available: let and let rec. The last one is used to define recursive functions, and they are fundamentally the same; the difference lies in scoping rules (e.g., when using let … in). Example of let rec:
let rec factorial n = if (n < 0) then failwith "negative factorial!" else if (n = 0) then 1 else n * factorial (n-1);;
- OCaml from the very beginning is a super nice intro book to the language. I gave it a 5/5 on Goodreads.
- Examples from the book: in this user repository.
- Logical operators are not exactly what you expect regarding equality: = and <>. Yeah, not ==. Annoying, huh?
- true and false are written in lowercase. Different from python, equal to ruby. Why are programming languages so different? At least, if you write it wrong, you are prompted with a nice message:
Error: Unbound constructor True Hint: Did you mean true?
- Speaking of messages, error messages from OCaml are veeeeeery good. It looks like its creators know how to actually communicate with other humans (gcc, this is a subtle sarcasm directed to you!). Want to see an example? I’ll give you one about a warning:
let f l = match l with  -> True;; (* Response: (yeah, this is a comment!) Warning 8: this pattern-matching is not exhaustive. Here is an example of a value that is not matched: _::_ val f : 'a list -> bool = <fun> *)
- Naming convention when deconstructing lists: h::t. This means head and tail. In haskell, we usually use x:xs.
- Oh yeah, haskell is : while OCaml is :: while in the lisp family of languages this is cons.
- And the append/concatenate operator is @. In haskell it is ++, in python it is +.
- Yeah, I keep comparing OCaml with other languages because I find it easier to understand it this way.
- A list in OCaml is a single linked list behind the scenes. So the :: operator only acts on one side of the list…you’re screwed if you want the other one — alternatively, revert the list or use a better data structure.
- Speaking about lists….[1;2;3;4] not [1,2,3,4]. The last style is from Python / Haskell / Ruby.
- Package manager? Yeah! opam. This should be analogous to RubyGems and Haskell’s Cabal or node’s npm. opam install, opam remove, opam search…I keep writing it opan, for some reason.
- I love this feature: every function in OCaml has only one parameter. Native currying (aka partial application) FTW! Like haskell.
- The compiler is pretty smart about inferring types, but annotations can be made too:
let sum10 (x:int):int = x + 10;;
- Anonymous functions:
fun x -> 2 * x (* example of use with map: *) map (fun x -> 2 * x) [1; 2; 3] (* yields [2; 4; 6] *)
- Just comparing with haskell, which is slightly smaller:
map (\x -> 2 * x) [1..3] -- or, better yet map (* 2) [1..3]
- Actually, it is possible to use something such as (+) or (<=) in OCaml. But…not (*). This is confused with a comment. Maybe there is a way of escaping this. Edit: yeah, we just have to insert spaces: ( * ).
I guess I’m stopping here for now. This includes up to chapter 6 of the aforementioned book, plus a few random sources on the web.