You are currently browsing the archives for the work tag.

Pattern matching in JavaScript

This morning I was wondering if it would be possible to do some kind of pattern matching using JavaScript. So I fired up my vim and I started coding just after lunch, and I'm pretty happy with what I came up with : the answer is yes.

If you are impatient, you can jump to the example page1. If you are not, please read on.

My first thought was that when one does pattern matching, the idea behind is to be able to discriminate values (über switch) and be able to deconstruct complex structures. The latter requires the use of variables in the pattern. Without touching to the syntax, it is tricky to come up with something more elegant than the following solution :

    // — snippet — //
    var id = Math.random ();
    var idname = Math.ceil (10000 * Math.random ());

    this.variable = function (name) {
      var o = {};
      o.name = name;
      o['__match_pattern_id'+idname] = id;
      return o;
    }

    function is_variable (s) {
     return (s &&
       s['__match_pattern_id'+idname] &&
       s['__match_pattern_id'+idname] == id);
    }
    // — snippet — //

Basically, each object is assigned to unique ids, and those are used to create objects which can be easily recognized without using too much black magic. The rest is pretty straightforward : it's some really basic one way unification, without any priority.

var m = new Match_Pattern ();
var _ = m.variable;

function fact (n) {
  return m.match(n,
  [
    [    0  , function ( ) { return 1                    }],
    [ _("n"), function (a) { return (a.n * fact(a.n -1)) }]
  ]);
}

The syntax is pretty clear too : match takes two arguments : first the element to match, and second an array of "couples" (in fact, arrays). Each of those contain a pattern and a function to call if the pattern is matched. As I said beford, all variables in the pattern are in fact dummy (recognizable) objects which will be detected while going down the structure of the pattern, and bound to the correct value.

There was one last point though : how to access the unified values in the function ? I went with the most obvious solution : dump everything in an object and pass it as an argument. This has one major drawback : it is not possible to use twice the same variable, but this is actually a good and sane thing.

Moreover, as I said before, there is no notion of priority based on how deep the matching goes, the first matched pattern is selected2. And there are of course no guards, though these would be quite easy to implement.

Feel free to comment.

Downloaded : 188 times
File : pattern_matching.js
Size: 2.7 ko
  1. Note : if something has cross browser problems, it's definitely the displaying functions, not the core []
  2. Actually, it works a lot like OCaml pattern matching works… []

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 : 77 times
File : ocaml_script_cgi.tar.gz
Size: 1.3 ko