A (very brief) guide to Ocaml+Ocsigen, for Haskell programmers.
Most of the time I’ve heard the suggestion that people learn OCaml first, then Haskell second. I did the reverse, and in learning (or beginning to learn) OCaml I wanted a guide aimed at Haskell programmers - people who already understand what immutability is, how functional programs are structured, static type inference, pattern matching, but had never touched the language/ecosystem before.
While picking up OCaml and then using it with the web framework Ocsigen over the last few days, here were some very brief notes that I took down of things that were not immediately apparent (and often took a lot of searching around/reading to find). The syntax is pretty easy - just check out a generic comparison or an introduction to ocaml and you should be fine; what was more difficult was getting familiar with the build ecosystem, as the core language seems a little less friendly by default than Haskell (at least with ghc —make and friends). Or perhaps that is just my bias by being more familiar with GHC/Haskell.
first step is making the toplevel more friendly: enter “topfind”!
#use "topfind";; #require "batteries";; (* or whatever *)this allows you to
#requireany package you want to have access to on the toplevel. to make it automatic whenever you run the toplevel, put the preceding in~/.ocamlinit. Also, at least on my system, readline is not supported by it. I saw (somewhere, sorry I don’t have the link anymore) that you can start the toplevel within another program to have proper history, line based navigation, etc. I just ran it from within emacs, with tuareg-mode (C-c C-s RET), and so got all of those benefits and more.[edit], mfp mentioned on reddit that two common wrappers for the toplevel are rlwrap and ledit[/edit]to build (and run) an executable:
ocamlfind ocamlc -package batteries -c some.ml ocamlfind ocamlc -o some -package batteries -linkpkg some.cmo ./some[edit]I’ve since realized (duh, perhaps) that you can also compile straight to native code, using the ocamlopt compiler. An example would be:ocamlfind ocamlopt -package batteries -linkpkg -o some some.mlAnd it is MUCH faster. (anecdotally, a naive solution to problem 3 on Project Euler ran in about 0.6 seconds via the former method, and about 0.1 seconds via ocamlopt.
[/edit]Also, notice that there is no concept of a ‘main’ function (as far as I can tell) - everything in the file is evaluated in order, so just stick you’re ‘main’ function at the bottom of the file (as anything it depends upon must already have been defined), in something like:
let _ = run_program[edit], again, comment from mfp that proper style is to write this as:let () = run_program ()[/edit]forget polymorphism! (almost) everything is specific. for example, when working with
BatBig_int’s, you have to useBatBig_int.(=)to compare them. (this is of course when you are using the batteries big_int library).when using caml4p (the preprocessor, which I started using to use an sqlite orm library), if you get a
Not_foundexception, it could be caused by putting-syntax camlp40instead of-syntax caml4poin the compilation command. seems (painfully, stupidly) obvious, but the error message does not make that clear.for ocsigen, if you need to link a package, you use something like
<extension findlib-package="batteries"/>in the config file. And of course build the .cmo file with-package batteries.everything is evaluated in order - this means that you can’t use something in a file before you have declared it. The only exception is with mutually recursive functions, which obviously need this. define them on the toplevel like:
let rec hello n = goodbye n and goodbye n = n+1;;- Use the batteries-included library (which might already be available for your distribution) . As far as I can tell, it is about comparable (though I haven’t used it extensively) as the standard library for haskell - ie
Prelude,Data.List, etc. Great documentation is available at the github page. It is a little confusing sometimes figuring out what functions are added byBatSomethingand what already exist inSomething. For example, the function List.map is listed in theBatListdocumentation, when it actually is fromList. But, it is pretty easy to figure out - load up batteries in the top level and try both.BatList.map;;will tell you that it does not exist,List.map;;will show the type of the function.[edit], another option, courtesy of mfp, via reddit, is to justopen Batteries, which then makes everything available in Something (neat!). This highlights that something I have not touched in this short post is the module system, because I haven’t explored it yet myself! It is reputed to be much more powerful than Haskell’s, so I’m excited to learn about it.[/edit].