"The Whitespace Thing" is an alternative syntax for OCaml that uses indentation to group multi-line expressions, like Python and Haskell. This is a controversial feature that some people will always love and some people will always hate. Using pretty much the same indentation patterns you put in your code anyway, "The Whitespace Thing" eliminates:
The syntax is otherwise the same as OCaml, with a few restrictions.
Version 1 is implemented as a line-oriented preprocessor, invoked as ocaml+twt. This is something of a hack. At some unspecified time in the future, Version 2 should be written as a camlp4 syntax (although this promises to be difficult).
Contents OCaml forge project page for source repository, bug reports, and feature requests |
The current version is 0.93, released on 2012-02-01. It works very well: I have used it exclusively for several years to implement computational biology algorithms and bioinformatics tools. However, in these travels I probably have not rigorously tested all pathological cases of syntax involving objects, modules, and functors.
The software is distributed under the MIT license.
Previous versions
twt-0.92.tar.gz ocaml+twt-0.91.tar.gzNote: version 0.90 is backwards-incompatible with previous versions. Older versions still required you to use in with let and indent the let body.
ocaml+twt-0.86.tar.gzTo install the preprocessor, run make install in the source tree. By default, this tries to install the executable in the same directory as ocamlc. Use make INSTALLDIR=/some/path install to override this.
To use the preprocessor, either manually invoke it using ocaml+twt mycode.ml and pipe the results to a file, or use the preprocessor flag to ocamlc:
ocamlc -pp ocaml+twt mycode.ml
There are a few options available for the preprocessor. They are pretty self-explanatory by looking at the usage printed by invoking ocaml+twt.
With ocamlbuild, you can have something like this in the _tags file in your project directory:
<**/*.ml> or <**/*.mli>: ocaml, pp(ocaml+twt), debug
If you use OCamlMakefile, you can make the first line of your file (*pp ocaml+twt *) in order to have it preprocessed.
Some camlp4 extensions can be used with ocaml+twt, by applying camlp4 to the output of ocaml+twt. There is a utility, ppcompose, included in the distribution to assist with this (see the README file).
Here is a handy quick reference that demonstrates most common syntax forms recognized by the preprocessor. The LaTeX source for this is included in the distribution. There are also several example programs included in the examples subdirectory.
ocaml | ocaml+twt |
let rec main magic_number = Printf.printf "Your guess? "; let guess = int_of_string (read_line ()) in if guess > magic_number then (Printf.printf "Too high!\n"; main magic_number) else if guess < magic_number then (Printf.printf "Too low!\n"; main magic_number) else (Printf.printf "You win!\n"; exit 0);; Random.self_init ();; main (Random.int 100);; |
let rec main magic_number = Printf.printf "Your guess? " let guess = int_of_string (read_line ()) if guess > magic_number then Printf.printf "Too high!\n" main magic_number else if guess < magic_number then Printf.printf "Too low!\n" main magic_number else Printf.printf "You win!\n" exit 0 Random.self_init () main (Random.int 100) |
let list_out lst = (List.map (function Some x -> x) (List.filter (function Some x -> true | None -> false) lst)) |
let list_out lst = List.map function Some x -> x List.filter function Some x -> true | None -> false lst |
for i = 1 to 10 do print_int i; print_newline () done; print_string "done" |
for i = 1 to 10 do print_int i print_newline () print_string "done" |
let contrived = function s when (String.length s) > 0 -> begin try Some (float_of_string s) with Failure _ -> Some nan end | _ -> None |
let contrived = function | s when (String.length s) > 0 -> try Some (float_of_string s) with | Failure _ -> Some nan | _ -> None |
More substantial examples can be found in the examples subdirectory of the source tree.
This mostly covers things for which there was not enough space in the quick reference:
instead of... | do... |
match n with | 1 -> print_string "one" print_endline () |
match n with | 1 -> print_string "one" print_endline () |
instead of... | do... |
if b then (+) else (-) x y |
(if b then (+) else (-)) x y |
function | x when x >= 0 -> (+) | _ -> (-) x y |
(function | x when x >= 0 -> (+) | _ -> (-)) x y |
Personally, I just use Fundamental mode with the following in my .emacs:
(global-set-key (quote [S-iso-lefttab]) (quote indent-relative-maybe))
This binds Shift-Tab to insert whitespace to match the indentation of the previous line.
For something fancier, Till Varoquaux has contributed caml+twt.el, which is still experimental. Thanks to Till! Here is more information:
I did a quick hack to Tuareg to get indentation working in python-mode like way. You will find the el file here enclosed. To autoload I use the following (warning to lisp lovers: this is very ugly, I'm just getting started with elisp). (autoload 'tuareg-mode "tuareg" "Major mode for editing Caml code" t) (autoload 'caml+twt-mode "caml+twt" "Major mode for editing Caml+twt code" t) (defun start-mlmode () (when (save-excursion (progn (goto-char (point-min)) (looking-at "(\\*pp ocaml\\+twt\\*)[:blank:]*") ) ) (caml+twt-mode) ;;(tuareg-mode) ) (remove-hook 'find-file-hook 'start-mlmode 1) ) (add-hook 'tuareg-load-hook ( lambda ()(add-hook 'find-file-hook 'start-mlmode 1)) Which will switch over to caml+twt mode on opening a file with a .ml extension only if the first line is: (*pp ocaml+twt*) (this is consistent with OCamlMakefile). Syntax highlighting of comments doesn't work anymore. Hope this turns out usefull to someone. Till
E-mail me if you want to call yourself a member. Actually, you don't have to e-mail me. In all likelihood, the only purpose of this club will be to get into flamewars.