You are currently browsing the archives for the ocaml tag.

8 facts about OCaml

OCaml is a language I've blogged about quite a few times, and this is normal: I use it a lot. I'd like today to talk about those little things I like and dislike in OCaml. I won't deal with the usual stuff here (static and strong typing, efficient compiler, functionnal language, etc.)

  • I like:
    • the elegance and conciseness of the language
    • the folds, wonderful for twisted minds
    • if it compiles, it works
    • quite a few other things, but I said I won't talk about strong, static typing ;)
  • I don't like
    • IO is shit: never use print_*, use Printf.
    • regular expressions
    • Gnagna has type t but is here used with type t', where one never know which of the two was inferred
    • did I mention the IO ?

Progress Bar in OCaml

The really annoying thing when I write programs which take a few minutes to complete some task is to know what amount of data has already been treated. Usually I use some text output to do so: the easiest solution is to compute the total number of steps (for eample the number of results in a MySQL query, or the number of elements in an array, etc.) and then at each step print the percentage of tasks already computed.

This works quite well, except your terminal gets filled with 1% 2% 3% 4% … and it's even worse if you add some line breaks.

The solution I use in OCaml is the following: a progress bar ala wget. In order to do that, I'll use two magical functions (which only work on ANSI terminals) :

let save_cursor () =
  print_string "\027[s"
let restore_cursor () =
  print_string "\027[u"

The first function saves the current location of the cursor and the second puts the cursor back to the saved position. The idea is pretty straightforward: first we save the current location, then we print the progress bar, then come back to the saved position, and start over.

I've written a quick module which help to achieve this (it does not deal with terminal resizing: the width of the progress bar will be around ~110 characters).

let width = 100

let total = ref 0
let state = ref 0
let last_up = ref 0

let save_cursor () =
  print_string "\027[s"
let restore_cursor () =
  print_string "\027[u"

let init t =
  total := t;
  state := 0;
  last_up := 0;
  save_cursor()

let do_bar n =
  restore_cursor();
  save_cursor();
  Printf.printf
    "[%s%s%s] %d%%%!"
    (String.make (n-1) '=')
    (if n = width then "=" else ">")
    (String.make (width-n) ' ')
    n;
 if n = width then print_newline()

let step () =
  incr state;
  let pc = (width * !state)/(!total) in
  if pc > !last_up then
    do_bar pc;
    last_up := pc

The advantage is that you just need to initialize the progress bar with the total number of steps and then call step () at each step. Nothing more. Magical!

Using OCaml to write web scripts - 2

Yesterday I have explained how to use an OCaml .ml script as an executable, and how to display a web page written in OCaml. I'll explain here how to parse a querystring.

The querystring is passed as the environment variable QUERY_STRING. I'll use the following module to fetch the querystring and parse it :

module Get =
  struct
    let query_string = try String.lowercase (Sys.getenv "QUERY_STRING") with
    Not_found -> ""

    let _Hash =
      let return = Hashtbl.create 23 in
      let rec split c = function
          "" -> []
        |s when s.[0] = c -> ""::(split c (String.sub s 1 ((String.length s)-1)))
        |s ->
          begin
            match (split c (String.sub s 1 ((String.length s)-1))) with
               [] -> [String.make 1 (s.[0])]
            |t::q -> ((String.make 1 (s.[0]))^t)::q
          end
      in
      let query_list = split ‘&’ query_string in
      let rec q2h = function
        [] -> ()
       |t::q ->  (
         q2h q;
         match (split ‘=’ t) with
            [] -> ()
          | arg::[] -> Hashtbl.add return arg ""
          | arg::value::_ -> Hashtbl.add return arg value;) in
      q2h query_list;
      return
    let arg x = try Hashtbl.find _Hash x with Not_found -> ""
    let iter f = Hashtbl.iter f _Hash
  end

This is a simple module which allows us to do some simple stuff. Speeking of which, here is a simple example :

let e s = print_string s

let print_arg_val x y = e ("<i>"^x^"</i> : "^y^"<br/>\n")

let fibo n =
  try
    let rec fibo = function
      0 -> 1
     |1 -> 1
     |n -> fibo (n-1) + fibo (n-2)
    in
    string_of_int (fibo (int_of_string n))
  with _ -> ""

let _ =
  e "Content-type: text/html\n\n";

  e "<a href=\"test.ml?arg1=val1&arg2=val2&arg3=val3&n=15\">Examples</a><br/><br/>\n";
 
  e "<b>Get.query_string</b> : <br/>\n";
  e (Get.query_string^"<br/>\n");
  e "<br/>\n";

  e "<b>Get.arg \"arg2\"</b> : <br/>\n ";
  e ((Get.arg "arg2")^"<br/>\n");
  e "<br/>\n";

  e "<b>fibo (Get.arg \"n\")</b> :<br/>\n";
  e (fibo (Get.arg "n"));
  e "<br/>\n";
  e "<br/>\n";

  e "<b>Get.iter print_arg_val</b> : <br/>\n";
  Get.iter print_arg_val;

Those are only simple examples, and there are a lot of things to improve in order to use this in a real website (for example the conversion of url encoded characters, etc.).

But as I stated previously, I did not aim to write a CGI module for OCaml : use ocamlcgi instead, this one was really written to be used in real life.

Moreover, the following module might be useful if you want to plug a MySQL database to a web app writtent in ocaml : ocaml-mysql.

Last, by using camlp4, it should be possible to write scripts which look more like some PHP, using (for example) this kind of syntax : <?caml () ?> (everything which is not between those should just be sent of the output).

As a conclusion, it is possible to write dynamic web pages in OCaml, but is it really useful ? OCaml's strong typing can be a real pain in such context (no

echo

function ala PHP, etc.) but someone might find something useful to it.

Downloaded : 138 times
File : ocaml_script_cgi.tar.gz
Size: 1.3 ko

Using OCaml to write web scripts

OCaml is a language in which you can do anyything. That's why I decided to use it to write CGI scripts. While it is really easy to use compiled code as a CGI, it is far less simple to use scripts.

Executable ML

Let's start with a very simple script :

print_endline "Hello OCaml !";

Basically, a ml file is not an executable, this can be is achieved in two phases, first a chmod + x on the file, and then we add the following lines in the header file:

#!/bin/sh
#(*
exec ocaml "$0" "$@"
*)
warnings "A";;

print_endline "Hello OCaml !";;

The shabang indicates that the interpreter to be used is /bin/sh (nothing new here).

The following three lines are an elegant trick: on the second line, # tells bash that the line is a comment, so it jumps to the new line and calls the toplevel, passing as arguments the name of the script and the rest of the command line.

On the OCaml side, everything which is between (* *) is considered as a comment : OCaml understands the second line as #warnings "A" which is used to display all warnings (alternatively, one can use #wargins "a" to hide all warnings)

Now one can test it by calling ./test.ml

A page saying "Hello OCaml"

The first thing to do is to tell Apache how .ml file should be dealt with, which is achieved by adding the following line to the .htaccess :

AddType cgi-script ml

Those know Python or Perl won't be suprised, we have to modify slightly our script in order to send the correct headers :

#!/bin/sh
#(*
exec ocaml "$0" "$@"
*)
warnings "A";;

print_string "Content-type: text/html\n\n";
print_endline "Hello OCaml !";;

Just check it in your browser ;)