Previous week Up Next week

Hello

Here is the latest Caml Weekly News, for the week of September 14 to 21, 2010.

  1. Create a constraint between variant type and data list
  2. LablGtk 2.14.2
  3. ancient module
  4. Other Caml News

Create a constraint between variant type and data list

Archive: http://groups.google.com/group/fa.caml/browse_thread/thread/172ab0d7ea227bd8#

Sylvain Le Gall asked:
I would like to somehow enforce that a variant type is associated with 
an entry in a data list. 

For example, 

I would like to define: 

type license = GPL | LGPL 

and 

let data = [ GPL, "GNU Public license"; 
             LGPL, "GNU Lesser General Public license" ] 

I would like to enforce that all variants of license are in the 
association list. 

I have tried to use polymorphic variants, but don't see how to enforce 
this constraint. 

The point, is that if I add a new variant to license (e.g. BSD3), the 
compiler output an error because this new variant is not in data list. 

Any ideas ? If you need to use another type expression rather than 
variant, please do so, as long as I am able to link the license type 
and data list. 
      
bluestorm suggested:
I do not have a direct solution to your problem. 

If you want to associate a data with each case, you can use a pattern 
matching, wich will do the exhaustiveness check : 

let to_string : license -> _ = function 
| `GPL -> "GPL" 
| `LGPL -> "LGPL" 

You will be warned if you add (or remove) some licenses and forget to 
change the function. 

You may, however, want to have a list of all licenses values, instead 
of a case-handling on each value. I don't know how you could have the 
compiler check completeness for you, but if you really want that 
check, there is an extra-linguistic method : declare your value 
without giving it a type annotation, so that the compiler will infer 
the covered case, then use a script outside the program, calling 
"ocamlc -i" to check the inferred signature, and comparing it to you 
datatype declaration. 

Finally, I have a third solution based on code generation : given my 
first solution (turning the association list into a function), what 
you need is only a list of all the constructors (and you can build 
your assoc list with List.map (fun x -> x, assoc_function x)). This 
can easily be generated from the datatype declaration using direct 
camlp4, or Markus Mottl's type-conv ( 
http://www.ocaml.info/home/ocaml_sources.html#toc11 ). 
      
Oleg suggested:
In other words, you would like a set of values of a distinct type, 
each of which is associated with a printable string. One should be 
able to add to the set in some `authorized way'; one should not be 
able to make a value of that distinct type in an unauthorized way 
(that is, by accident). Right? 

It seems the following solution then would satisfy the specification: 

module LICENSE : sig 
  type t 
  val print_lic : t -> string 
  val gpl  : t 
  val lgpl : t 
  (* more can be added *) 
end = struct 
  type t = string 
  let print_lic x = x 
  let gpl  = "GNU Public license" 
  let lgpl = "GNU Lesser General Public license" 
end;; 

(* Usage example *) 
type package = {pkg_name : string; pkg_lic : LICENSE.t};; 
let packages = [{pkg_name = "gcc";    pkg_lic = LICENSE.gpl}; 
                {pkg_name = "lgpled"; pkg_lic = LICENSE.lgpl}] 
;; 
let rec pr_lics = function [] -> () 
 | {pkg_lic = l}::t -> Printf.printf "%s\n" (LICENSE.print_lic l); 
                       pr_lics t 
;; 
let rec all_of_lic l = function [] -> [] 
  | {pkg_name = name; pkg_lic = l'}::t when l' == l -> name :: all_of_lic l t 
  | _::t -> all_of_lic l t 
;; 

all_of_lic LICENSE.lgpl packages;; 

One can't overlook specifying the description string. One can't create 
new values of the type LICENSE.t `by accident' (the only possible 
values of the type are the ones exported by the module). 
      
Maxence Guesdon suggested:
Here is another solution, based on oug[1]. The idea is to:
1. make oug analyse your source files and dump the result,
2. write a program loading the dump and performing the checks you want.

Here is an example, which performs 1. and 2., with only one source file
"foo.ml".

=== myoug.ml
let (data, _) = Ouglib.Analyze.analyze ["foo.ml"];;

let number_variants =
 Ouglib.Lang.filter_elements data
   (Ouglib.Lang.Name
    {
      Ouglib.Lang.sel_name = "Foo.number.*" ;
      sel_kind = [ Ouglib.Data.Type_field ] ;
    }
   )
;;

let numbers_list_id =
 match
   Ouglib.Lang.filter_elements data
     (Ouglib.Lang.Name
      {
        Ouglib.Lang.sel_name = "Foo.numbers" ;
        sel_kind = [ Ouglib.Data.Value ] ;
      }
     )
 with
   [id] -> id
 | _ -> assert false
;;

let graph = data.Ouglib.Data.graph ;;
let created_by_numbers_list =
 let l = Ouglib.Graph.succ graph numbers_list_id in
 let f acc (id, k) =
   match k with
     Ouglib.Data.Create -> id :: acc
   | _ -> acc
 in
 List.fold_left f [] l
;;

let (_,missing) =
 List.partition (fun id -> List.mem id created_by_numbers_list) number_variants
;;

match missing with
 [] -> exit 0
| _ ->
   let b = Buffer.create 256 in
   Ouglib.Dump.print_element_list data b  missing;
   prerr_endline
     (Printf.sprintf "The following constructors are not present in Foo.numbers:\n%s"
      (Buffer.contents b)
     );
   exit 1
;;
=== /myoug.ml ==

=== foo.ml ===
type number = One | Two | Three | Four;;

let numbers = [ One, 1 ; Two, 2 ];;
=== /foo.ml ==

Compilation of myoug.ml to myoug.x:
# ocamlc -I +oug str.cma toplevellib.cma oug.cma -o myoug.x myoug.ml 

Launching myoug.x gives the following:
The following constructors are not present in Foo.numbers:
f Foo.number.Three
f Foo.number.Four

Of course, you can adapt the program to fit your needs: have a makefile
target to create the oug dump and use this dump in various checking
programs, or in one program performing various checks.

Hope this helps,

Maxence

[1] http://home.gna.org/oug/index.fr.html
      
Finally, Sylvain Le Gall said:
Thank you for all your answer. I pick the one from oleg@okmij.org, I
hide the license with a type and the creation of license is done in the
module. The to_string/from_string is done by registering extra data in
an Hashtable.

See the implementation here.
http://darcs.ocamlcore.org/cgi-bin/darcsweb.cgi?r=oasis;a=headblob;f=/src/oasis/OASISLicense.mli
http://darcs.ocamlcore.org/cgi-bin/darcsweb.cgi?r=oasis;a=headblob;f=/src/oasis/OASISLicense.ml
      

LablGtk 2.14.2

Archive: http://groups.google.com/group/fa.caml/browse_thread/thread/e56d92a25216b3e7#

Jacques Garrigue announced:
Following a number of bug fixes, and particularly a serious
incompatibility in ocaml 3.12 (due to the fixing of an old typing
bug), here is a new release of LablGtk2, the ocaml interface to the
Gtk+ GUI library and friends (glade, rsvg, gnomecanvas, gnomedruid,
panel, gtkspell, gtksourceview2.)

You can find it at:

 http://wwwfun.kurims.kyoto-u.ac.jp/soft/olabl/lablgtk.html

The windows release will have to wait for a windows version of ocaml
3.12...


$Id: CHANGES 1528 2010-09-17 08:38:54Z garrigue $

In Lablgtk-2.14.2:

2010.09.09 [Jacques]
 * add GtkCurve (but it is deprecated since 2.20)

2010.08.16 [Jacques]
 * rename g_value_{get,set}_variant, as the name is used by recent
   versions of glib (reported by Florent Monnier)

2010.07.25 [Jacques]
 * add changed signal to cell_renderer_combo (reported by Dmitry Bely)

2010.07.23 [Jacques]
 * copy GtkTreePath arguments in callbacks, as reported by Benjamin.

2010.06.25 [Jacques]
 * remove gtkInit.cmo from gdk_pixbuf_mlsource, no need to
   initialize Gtk as Gobject is sufficient 
 * protect GtkThread callbacks against exceptions, and provide a
   function to process messages inside a different main loop.
 * add -nothinit option to lablgtk2, since Quartz cannot run the main
   loop in a different thread (one should just call GtkThread.main).
   See dialog-thread.ml for an example.

2010.06.08 [Jacques]
 * correct interfaces due to the fixing of an unsoundness bug in ocaml 3.12
   (cf. http://caml.inria.fr/mantis/view.php?id=4824) 
      

ancient module

Archive: http://groups.google.com/group/fa.caml/browse_thread/thread/6b19493f7d449b91#

Yoann Padioleau asked, Richard Jones replied, and Gerd Stolpmann said:
> > I am trying to use your Ancient module to avoid having the garbage
> > collector spends lots of time iterating over huge data in memory. It
> > works quite well for arrays but for hashtbl I have some problems
> > where I am not able to find back keys that were clearly in the
> > original hashtbl (before Ancient.mark it).
> >
> > In the doc it says: 
> > 
> > (1) Ad-hoc polymorphic primitives (structural equality, marshalling
> > and hashing) do not work on ancient data structures, meaning that you
> > will need to provide your own comparison and hashing functions.  
> 
> The issue is described by Xavier Leroy:
> http://caml.inria.fr/pub/ml-archives/caml-list/2006/09/977818689f4ceb2178c592453df7a343.en.html
> 
> As far as my understanding goes, what happens is that the OCaml
> compare function (or some C equivalent in the runtime) looks at the
> two string pointers and decides that since both are out of the normal
> heap they are just opaque objects.  Thus it won't compare the content
> of the strings, but will just do pointer equality.  This massively
> breaks assumptions in some ordinary OCaml code, in this instance in
> Hashtbl.

There is now a way to change this. You can call caml_page_table_add
(since 3.11) to explicitly declare a memory region as containing Ocaml
values. The polymorphic comparison, the hash primitive, and marshalling
work then.

There is support for this in Ocamlnet-3:

http://projects.camlcity.org/projects/dl/ocamlnet-3.0.3/doc/html-main/Netsys_mem.html#VALvalue_area
      

Other Caml News

From the ocamlcore planet blog:
Thanks to Alp Mestan, we now include in the Caml Weekly News the links to the
recent posts from the ocamlcore planet blog at http://planet.ocamlcore.org/.

Compiler tip:
  http://gaiustech.wordpress.com/2010/09/20/ocaml-compiler-errors/

Code folding in Emacs:
  http://gaiustech.wordpress.com/2010/09/20/code-folding-in-emacs/

Onotify:
  https://forge.ocamlcore.org/projects/onotify/

Parametric Modular Programming:
  http://alaska-kamtchatka.blogspot.com/2010/09/parametric-modular-programming.html
      

Old cwn

If you happen to miss a CWN, you can send me a message and I'll mail it to you, or go take a look at the archive or the RSS feed of the archives.

If you also wish to receive it every week by mail, you may subscribe online.


Alan Schmitt