Basic interaction

IOCaml is a basic OCaml kernel for IPython.

Code can be written in notebook cells and is executed by the OCaml toploop when ctrl-return or shift-return is pressed

In [1]:
let a = 23

val a : int = 23

Note that you do not need ";;" at the end of the statement. The code in each cell is read as if it were a file being loaded into the top loop. Multiple expressions can be entered in each cell.

In [2]:
let b = "hello"
let c = "world"
let d = b ^ " " ^ c

val b : string = "hello"
val c : string = "world"
val d : string = "hello world"

You can load system libraries as normal.

In [3]:
#use "topfind"

- : unit = ()
Findlib has been successfully loaded. Additional directives:
  #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 = ()

In [4]:
#require "bigarray"

/home/andyman/.opam/4.01.0/lib/ocaml/unix.cma: loaded
/home/andyman/.opam/4.01.0/lib/ocaml/bigarray.cma: loaded

In [5]:

- : ('a, 'b, 'c) Bigarray.Array1.t -> int = <fun>

Errors are labelled with file [cell number]

In [6]:
let a = 1
let b = 2
let c = a + b + 1.0

val a : int = 1
val b : int = 2
File "[6]", line 3, characters 16-19:
Error: This expression has type float but an expression was expected of type
Characters 36-39:
  let c = a + b + 1.0

Basic output

There are three basic output types; messages from the compiler, stdout and stderr. All three are sent to the notebook.

In [7]:
Printf.printf "hello";
Printf.fprintf stderr "world"

- : unit = ()

Data is sent to the current cell as it is generated.

In [8]:

/home/andyman/.opam/4.01.0/lib/ocaml/threads: added to search path
/home/andyman/.opam/4.01.0/lib/ocaml/threads/threads.cma: loaded

In [9]:
Thread.create (fun () -> for i=0 to 5 do Printf.printf "hello world %i\n%!" i; Unix.sleep 1 done) ()

hello world 0
- : Thread.t = <abstr>
hello world 1
hello world 2
hello world 3
hello world 4
hello world 5

The current cell is the one just executed, so the above could get confusing...

In [10]:
Thread.create (fun () -> for i=0 to 5 do Printf.printf "hello world %i\n%!" i; Unix.sleep 1 done) ()

hello world 0
- : Thread.t = <abstr>
hello world 1
hello world 2

In [11]:
Printf.printf "hello world in the middle\n%!"

hello world in the middle
- : unit = ()
hello world 3
hello world 4
hello world 5

Iocaml API

Some functions are available for controlling interaction with the toploop and notebook in the Iocaml module

In [12]:
#require "iocaml"

There are a few functions for disabling output.

In [13]:

- : bool -> unit = <fun>
- : bool -> unit = <fun>
- : bool -> unit = <fun>
- : bool -> unit = <fun>

In [14]:
Iocaml.suppress_stdout true;
Printf.printf "where am I?\n%!";
Iocaml.suppress_stdout false;
Printf.printf "I'm back!\n%!";

I'm back!
- : unit = ()

The kernel has a command line option -package pkg which automatically #use's topfind and loads the required package. It can be specified multiple times to load extra packages. The default ipython configuration file automatically loads the iocaml package.

Rich media output

Data can be sent to the front end and displayed as media. The Iocaml API provides 2 ways to do this.

In [15]:

- : ?base64:bool -> string -> string -> unit = <fun>

Iocaml.display ~base64 mime_type "data to display" displays the data with the given mime type. The optional base64 parameter will encode the data if that is required.

In [16]:

- : out_channel = <abstr>
- : ?base64:bool -> string -> unit = <fun>

Alternatively data can be written to Iocaml.mime : out_channel. When all the data is ready call Iocaml.send_mime ~base64 mime_type to display it.

HTML output

In [17]:
Iocaml.display "text/html" "<b>hello </b><i>world</i>"

hello world
- : unit = ()

This is a more complex example which renders a string array array as a table

In [18]:
open Printf
let to_table a = 
    let open Iocaml in
    let open Printf in
    fprintf mime "<table>\n";
    Array.iter (fun data -> 
        fprintf mime "<tr>\n";
        Array.iter (fun data -> 
            fprintf mime "<td>%s</td>" data
        ) data;
        fprintf mime "</tr>\n";
    ) a;
    fprintf mime "</table>"

val to_table : string array array -> unit = <fun>

In [19]:
to_table (Array.init 8 (fun row -> Array.init 6 (fun col -> sprintf "row=%i col=%i\n" row col)));;
Iocaml.send_mime "text/html"

row=0 col=0 row=0 col=1 row=0 col=2 row=0 col=3 row=0 col=4 row=0 col=5
row=1 col=0 row=1 col=1 row=1 col=2 row=1 col=3 row=1 col=4 row=1 col=5
row=2 col=0 row=2 col=1 row=2 col=2 row=2 col=3 row=2 col=4 row=2 col=5
row=3 col=0 row=3 col=1 row=3 col=2 row=3 col=3 row=3 col=4 row=3 col=5
row=4 col=0 row=4 col=1 row=4 col=2 row=4 col=3 row=4 col=4 row=4 col=5
row=5 col=0 row=5 col=1 row=5 col=2 row=5 col=3 row=5 col=4 row=5 col=5
row=6 col=0 row=6 col=1 row=6 col=2 row=6 col=3 row=6 col=4 row=6 col=5
row=7 col=0 row=7 col=1 row=7 col=2 row=7 col=3 row=7 col=4 row=7 col=5
- : unit = ()
- : unit = ()

You can embed images from a url with html.

In [20]:
Iocaml.display "text/html" "<img src=\"\" width=\"400\" height=\"400\"></image>"

- : unit = ()

PNG images

Images work similarly except they require base64 encoding.

In [21]:
let () = Iocaml.suppress_all true;;
#mod_use "/home/andyman/dev/tools/ocaml/iocaml/iocaml/";;
let width, height = 32,32;;
let pixels = Array.init (width*height) (fun i -> i);;

In [22]:
Iocaml.suppress_all false;
Png.write_png_chnl Iocaml.mime pixels width height;
Iocaml.send_mime ~base64:true "image/png"

- : unit = ()