(* When an OCaml source file is compiled, it becomes a module. The name
of the module is the capitalized form of the filename. For example,
if the source file is "my_module.ml", the module name is "My_module".
Modules can also be created explicitly within a source file. If
"my_module.ml" contains "module Foo = struct ... end", a module named
"My_module.Foo" will be created.
Here is an example of the definition and use of two modules within a
single source file: *)moduleAlpha = structlet name = "first"endmoduleOmega = structlet name = "last"endlet() =
Printf.printf "Alpha is %s, Omega is %s.\n"Alpha.name Omega.name
(* Alpha is first, Omega is last. *)(*-----------------------------*)(* The "#use" and "#load" commands are known as toplevel directives.
They can only be used while interacting with the interpreter or from
scripts that are run using the "ocaml" program. *)(* "#use" loads a source file into the current scope. *)#use "FileHandle.ml";;(* "#load" loads a module from a compiled bytecode file. This has the
same effect as including this file during bytecode compilation. *)#load "FileHandle.cmo";;(* "#load" can be used with libraries as well as modules. Bytecode
libraries use an extension of ".cma". *)#load "library.cma";;(* The "open" statement can be used in any source file. It allows any
values defined within a module to be used without being prefixed by
the module name. *)openFileHandle(* Modules form a hierarchy; submodules can be opened in a similar
fashion by prefixing them with the parent module's name. *)openCards.Poker(* It is often convenient to use Gerd Stolpmann's "findlib" system,
which makes it considerably easier to load libraries into the
interpreter. *)##use "topfind";;
- : unit = ()Findlib has been successfully loaded. Additionaldirectives:#require "package";;to load a package
#list;;to list the available packages
#camlp4o;;to load camlp4 (standard syntax)#camlp4r;;to load camlp4 (revised syntax)#predicates "p,q,...";;to set these predicates
Topfind.reset();;to force that packages will be reloaded
#thread;;to enable threads
- : unit = ()##require "extlib";;
/usr/lib/ocaml/3.10.2/extlib: added to search path
/usr/lib/ocaml/3.10.2/extlib/extLib.cma: loaded
(* The above use of "#require" has the same effect as typing the
following: *)#directory "+extlib";;#load "extLib.cma";;(* More information on the "findlib" system is available here:
http://projects.camlcity.org/projects/findlib.html
The "#directory" directive above is built into OCaml and allows
you to add additional directories to the path that is searched
when loading modules. You can use a prefix of '+' to indicate that
the directory is under the standard library path, which is usually
something like "/usr/lib/ocaml/3.10.2/".
Modules can be easily aliased using assignment. This will also
cause the interpreter to output the module's signature, which
can be used as a quick reference. *)#moduleS = ExtString.String;;moduleS :
sigval init : int ->(int -> char)-> string
val find : string -> string -> int
val split : string -> string -> string * string
val nsplit : string -> string -> string list
val join : string -> string list -> string
...
end#S.join;;
- : string -> string list -> string = <fun>
(* Many useful libraries can be found at The Caml Hump:
http://caml.inria.fr/cgi-bin/hump.cgi *)

(* Interfaces, also known as module types or signatures, are usually
saved in files with the same name as the corresponding module but
with a ".mli" extension. For instance, if the module is defined in
"YourModule.ml", the interface will be in "YourModule.mli". *)(* YourModule.mli *)val version : string
(* YourModule.ml *)let version = "1.00"(* As with modules, interfaces can also be defined explicitly inside
of a source file. *)moduletypeYourModuleSignature =
sigval version : string
endmoduleYourModule : YourModuleSignature =
structlet version = "1.00"end(* Signatures can also be anonymous. *)moduleYourModule :
sigval version : string
end =
structlet version = "1.00"end

(* Due to static typing, missing modules are detected at compilation
time, so this is not normally an error you can catch (or need to).
When using ocaml interactively or as an interpreter, the "#load"
directive can fail, resulting in a message like the following:
Cannot find file <filename>.
being printed to standard output. This is also not an error you can
catch, and its occurrence will not stop the script from executing.
It is possible to dynamically load modules and detect the failure of
this operation with Dynlink. An example is given in the next recipe. *)

(* This is very difficult to do in OCaml due to the lack of reflection
capabilities. Determining the current module name is reasonably easy,
however, by using the __FILE__ constant exposed by camlp4's macro
extensions. *)(*pp camlp4of *)let __MODULE__ = String.capitalize (Filename.chop_extension __FILE__)let() = Printf.printf "I am in module %s\n" __MODULE__

(* To add a directory to the module include path, pass the "-I" option
to any of the compiler tools. For example, if you have a module in
~/ocamllib called Utils with a filename of utils.cmo, you can build
against this module with the following: *)
$ ocamlc -I ~/ocamllib utils.cmo test.ml -o test
(* Within the toplevel interpreter, and from ocaml scripts, you can use
the "#directory" directive to add directories to the include path: *)#directory "/home/myuser/ocamllib";;#load "utils.cmo";;(* In both cases, prefixing the include directory with a '+' indicates
that the directory should be found relative to the standard include
path. *)#directory "+pcre";;#load "pcre.cma";;(* If you have findlib installed, you can print out the include path by
typing "ocamlfind printconf path" at the command line. *)
$ ocamlfind printconf path
/usr/local/lib/ocaml/3.10.2
/usr/lib/ocaml/3.10.2
/usr/lib/ocaml/3.10.2/METAS(* Instead of keeping a directory of ".cmo" (or ".cmx") files, you may
prefer to build a library (".cma" for bytecode, ".cmxa" for native).
This will pack all of your modules into a single file that is easy to
use during compilation: *)
$ ocamlc -a slicer.cmo dicer.cmo -o tools.cma
$ ocamlc tools.cma myprog.ml -o myprog

(* The easiest way to prepare a library for distribution is to build with
OCamlMakefile and include a META file for use with findlib.
OCamlMakefile is available here:
http://www.ocaml.info/home/ocaml_sources.html#OCamlMakefile
findlib is available here:
http://projects.camlcity.org/projects/findlib.html *)(* Put the following in a file called "Makefile" and edit to taste: *)OCAMLMAKEFILE = OCamlMakefileRESULT = mylibrary
SOURCES = mylibrary.mli mylibrary.ml
PACKS = pcre
all: native-code-library byte-code-library
install: libinstall
uninstall: libuninstall
include $(OCAMLMAKEFILE)(* Put the following in a file called "META" and edit to taste: *)
name = "mylibrary"
version = "1.0.0"
description = "My library"
requires = "pcre"
archive(byte) = "mylibrary.cma"
archive(native) = "mylibrary.cmxa"(* Now you can build bytecode and native libraries with "make" and
install them into the standard library location with "make install".
If you make a change, you will have to "make uninstall" before you
can "make install" again. Once a library is installed, it's simple
to use: *)
$ ledit ocaml
ObjectiveCaml version 3.10.2##use "topfind";;
- : unit = ()Findlib has been successfully loaded. Additionaldirectives:#require "package";;to load a package
#list;;to list the available packages
#camlp4o;;to load camlp4 (standard syntax)#camlp4r;;to load camlp4 (revised syntax)#predicates "p,q,...";;to set these predicates
Topfind.reset();;to force that packages will be reloaded
#thread;;to enable threads
- : unit = ()##require "mylibrary";;
/usr/lib/ocaml/3.10.2/pcre: added to search path
/usr/lib/ocaml/3.10.2/pcre/pcre.cma: loaded
/usr/local/lib/ocaml/3.10.2/mylibrary: added to search path
/usr/local/lib/ocaml/3.10.2/mylibrary/mylibrary.cma: loaded
(* To compile against your new library, use the "ocamlfind" tool as a
front-end to "ocamlc" and "ocamlopt": *)
$ ocamlfind ocamlc -package mylibrary myprogram.ml -o myprogram
$ ocamlfind ocamlopt -package mylibrary myprogram.ml -o myprogram

(* OCaml supports native compilation. If module load time is an issue,
it's hard to find a better solution than "ocamlopt". If compilation
is slow as well, try "ocamlopt.opt", which is the natively-compiled
native compiler. *)

(* There are two built-in functions that raise standard exceptions.
Many standard library functions use these. "invalid_arg" raises
an Invalid_argument exception, which takes a string parameter: *)let even_only n =
if n land1 <> 0(* one way to test *)theninvalid_arg(string_of_int n);(* ... *)()(* "failwith" raises a Failure exception, which also takes a string
parameter (though it is typically used to identify the name of
the function as opposed to the argument). *)let even_only n =
if n mod2 <> 0(* here's another *)thenfailwith"even_only";(* ... *)()(* In most cases, it is preferable to define your own exceptions. *)exceptionNot_evenof int
let even_only n =
if n land1 <> 0thenraise(Not_even n);(* ... *)()(* OCaml does not provide a facility for emitting warnings. You can
write to stderr, which may be an acceptable substitute. *)let even_only n =
let n =
if n land1 <> 0(* test whether odd number *)then(Printf.eprintf "%d is not even, continuing\n%!" n; n + 1)else n in(* ... *)()

(* Building libraries with C code is much easier with the aid of
OCamlMakefile. The following Makefile is all it takes to build
the "time" library from the previous recipe: *)OCAMLMAKEFILE = OCamlMakefileRESULT = time
SOURCES = time.idl
NOIDLHEADER = yes
all: byte-code-library native-code-library
include $(OCAMLMAKEFILE)(* Now, a simple "make" will perform the code generation with camlidl
and produce static and dynamic libraries for bytecode and native
compilation. Furthermore, "make top" will build a custom toplevel
interpreter called "time.top" with the Time module built in: *)
$ ./time.top
ObjectiveCaml version 3.10.2#Time.gettimeofday None;;
- : int * Time.timeval =
(0, {Time.tv_sec = 1217483550l;Time.tv_usec = 645204l})(* With the addition of a "META" file combined with the "libinstall"
and "libuninstall" targets, this library can be installed to the
standard location for use in other projects. See recipe 12.8,
"Preparing a Module for Distribution", for an example. *)

(** Documentation for OCaml programs can be generated with the ocamldoc
tool, included in the standard distribution. Special comments like
this one begin with two asterisks which triggers ocamldoc to
include them in the documentation. The first special comment in a
module becomes the main description for that module. *)(** Comments can be placed before variables... *)val version : string
(** ...functions... *)val cons : 'a -> 'a list -> 'a list
(** ...types... *)type choice = Yes|No|Maybeof string
(* ... and other constructs like classes, class types, modules, and
module types. Simple comments like this one are ignored. *)(** {2 Level-two headings look like this} *)(** Text in [square brackets] will be formatted using a monospace font,
ideal for identifiers and other bits of code. Text written in curly
braces with a bang in front {!Like.this} will be hyperlinked to the
corresponding definition. *)(* To generate HTML documentation, use a command like the following: *)
$ ocamldoc -html -d destdir Module1.mli Module1.ml ...
(* To generate Latex documentation, use a command like the following: *)
$ ocamldoc -latex -d destdir Module1.mli Module1.ml ...
(* If you use OCamlMakefile, you can type "make doc" to build HTML and
PDF documentation for your entire project. You may want to customize
the OCAMLDOC and DOC_FILES variables to suit your needs. *)