| 
  • If you are citizen of an European Union member nation, you may not use this service unless you are at least 16 years old.

  • Introducing Dokkio, a new service from the creators of PBworks. Find and manage the files you've stored in Dropbox, Google Drive, Gmail, Slack, and more. Try it for free today.

View
 

Col

Page history last edited by PBworks 13 years, 6 months ago

Intro

 

Col is a syntax library for OCaml for a compact and safe definition of IO functions on lists of flat records.

 

One type definition in a record-like syntax is expanded into a regular type definition of a record type, a tuple type and a class, plus many conversion functions which would have to be written manually otherwise. List of such objects can be loaded from and saved to CSV files with a header describing each field (column). You can edit these files manually, possibly by inserting new columns, and yet these files remain readable by your program.

 

See http://martin.jambon.free.fr/col-doc.html for an illustration of a program and the result after preprocessing. Hopefully it is self-explanatory. You can notice that the interface (doc.mli) which is automatically generated is much longer than the source implementation (doc.ml ~80 lines). After preprocessing, the implementation (doc.ppo) is truly huge (~800 lines), so it might take a while to compile.

 

Documentation

 

There is no documentation but there is a complete example at http://martin.jambon.free.fr/col-doc.html

 

Changes

 

version 1.1.1:

  • added support for predefined record and variant types, i.e. it defines functions that work over an existing type from a given library; this is done by inserting a new "predefined" keyword after the equal sign;
  • added support for traditional variants, mostly for compatibility with existing libraries that don't use polymorphic variants.

 

version 1.1.0: added functions for custom sort. Modules which are used to define custom types must now define a comparison function named "compare" (use "let compare = compare" if you want to use OCaml's default or if you don't want to use the comparison functions).

 

Examples

 

Here is a short example which defines a list of 2 records and saves them:

 

(* File test.ml *)
type col t = { x : float;
               y : float;
               title "The Title" : string = "no title" }

let data =
  let x = 1. in
  [ T.create ~x ~y:2. ();
    T.create ~y:4. ~x ~title:"line2" () ]

let _ = T.save_csv "data.csv" data

$ ocamlfind ocamlopt -o testcol test.ml -syntax camlp4o -package col -linkpkg
$ ./testcol
$ cat data.csv
x,y,"The Title"
1.,2.,"no title"
1.,4.,line2
$

 

 

Bugs

 

Installation

 

There is a bug in OCaml 3.09.1 which prevents from pr_o.cmo from working correctly (Stack overflow while executing something like "camlp4o pr_o.cmo ..."). The bug is not present in 3.08.4 and has been fixed in 3.09.2. If you are having this problem, compile with:

make common bc nc

(instead of "make" alone)

 

User Questions

 

Could you give an example of loading col from the toplevel using ocamlfind?

 

A: Like other findlib packages that provide a camlp4 syntax extension, you have to specify manually that you want to use "camlp4o", which correspond to the regular OCaml syntax support in camlp4. Actually I don't know if it would be possible to define a findlib package or sub-package that would do this automatically. Anyway the steps are the following:

  • #use "topfind";;
  • #camlp4o;;
  • #require "col";;

 

Note that if you are just interested in knowing which types and functions are made available by a given "type col" definition, using ocamlc or ocamlopt with the -i option may be a better choice than using the toplevel, e.g.

ocamlfind ocamlopt -i -syntax camlp4o -package col yourfile.ml > yourfile.mli

 

Here is a simple toplevel session; as you can see, the output is long:

        Objective Caml version 3.08.4

# #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 = ()
# #camlp4o;;
/home/martin/godi/lib/ocaml/std-lib/camlp4: added to search path
/home/martin/godi/lib/ocaml/std-lib/camlp4/camlp4o.cma: loaded
        Camlp4 Parsing version 3.08.4

# #require "col";;             
/home/martin/godi/lib/ocaml/site-lib/col: added to search path
/home/martin/godi/lib/ocaml/site-lib/col/pa_col.cmo: loaded
/home/martin/godi/lib/ocaml/site-lib/col/run_col.cmo: loaded
# type col point = { x : float; y : float };;
 type point = { x : float; y : float; }
 module Point :
  sig
    val create : x:float -> y:float -> unit -> point
    val create_tuple : x:float -> y:float -> unit -> float * float
    class obj :
      x:float ->
      y:float ->
      unit ->
      object
        val y : float
        val x : float
        method x : float
        method y : float
      end
    exception Bad_format
    val x_of_string : string -> float
    val x_to_string : float -> string
    val y_of_string : string -> float
    val y_to_string : float -> string
    type t = point
    module Index : sig val x : int val y : int end
    module Compare : sig val x : 'a -> 'a -> int val y : 'a -> 'a -> int end
    val fields : string array
    val labels : string array
    val of_array : string array -> point
    val to_array : point -> string array
    exception Invalid_field of string
    exception Invalid_label of string
    val type_float_field : string -> t -> float
    val type_float_label : string -> t -> float
    val load_csv_rows :
      ?strict:bool -> ?noheader:bool -> string -> (point -> unit) -> unit
    val load_csv :
      ?strict:bool -> ?noheader:bool -> ?rev:bool -> string -> point list
    val open_out_csv :
      ?sep:char ->
      ?noheader:bool -> string -> (point -> unit) * (unit -> unit)
    val save_csv_rows :
      ?sep:char -> ?noheader:bool -> string -> (unit -> point option) -> unit
    val save_csv :
      ?sep:char -> ?noheader:bool -> string -> point list -> unit
    val compare_fields :
      [< `Custom of point -> point -> int | `Down of string | `Up of string ]
      list -> point -> point -> int
    val compare_labels :
      [< `Custom of point -> point -> int | `Down of string | `Up of string ]
      list -> point -> point -> int
    module Tup :
      sig
        type t = float * float
        val create : x:float -> y:float -> unit -> float * float
        val of_array : string array -> float * float
        val to_array : float * float -> string array
        val of_record : point -> t
        val to_record : t -> point
        val get_x : t -> float
        val get_y : t -> float
        exception Invalid_field of string
        exception Invalid_label of string
        val type_float_field : string -> t -> float
        val type_float_label : string -> t -> float
        val load_csv_rows :
          ?strict:bool ->
          ?noheader:bool -> string -> (float * float -> unit) -> unit
        val load_csv :
          ?strict:bool ->
          ?noheader:bool -> ?rev:bool -> string -> (float * float) list
        val open_out_csv :
          ?sep:char ->
          ?noheader:bool ->
          string -> (float * float -> unit) * (unit -> unit)
        val save_csv_rows :
          ?sep:char ->
          ?noheader:bool ->
          string -> (unit -> (float * float) option) -> unit
        val save_csv :
          ?sep:char ->
          ?noheader:bool -> string -> (float * float) list -> unit
        val compare_fields :
          [< `Custom of t -> t -> int | `Down of string | `Up of string ]
          list -> t -> t -> int
        val compare_labels :
          [< `Custom of t -> t -> int | `Down of string | `Up of string ]
          list -> t -> t -> int
      end
    module OO :
      sig
        class t : x:float -> y:float -> unit -> obj
        val create : x:float -> y:float -> unit -> t
        val of_array : string array -> t
        val to_array : < x : float; y : float; .. > -> string array
        val of_record : point -> t
        val to_record : < x : float; y : float; .. > -> point
        exception Invalid_field of string
        exception Invalid_label of string
        val type_float_field : string -> t -> float
        val type_float_label : string -> t -> float
        val load_csv_rows :
          ?strict:bool -> ?noheader:bool -> string -> (t -> unit) -> unit
        val load_csv :
          ?strict:bool -> ?noheader:bool -> ?rev:bool -> string -> t list
        val open_out_csv :
          ?sep:char ->
          ?noheader:bool ->
          string -> (< x : float; y : float; .. > -> unit) * (unit -> unit)
        val save_csv_rows :
          ?sep:char ->
          ?noheader:bool ->
          string -> (unit -> < x : float; y : float; .. > option) -> unit
        val save_csv :
          ?sep:char ->
          ?noheader:bool ->
          string -> < x : float; y : float; .. > list -> unit
        val compare_fields :
          [< `Custom of
               (< x : 'b; y : 'c; .. > as 'a) ->
               (< x : 'b; y : 'c; .. > as 'd) -> int
           | `Down of string
           | `Up of string ]
          list -> 'a -> 'd -> int
        val compare_labels :
          [< `Custom of
               (< x : 'b; y : 'c; .. > as 'a) ->
               (< x : 'b; y : 'c; .. > as 'd) -> int
           | `Down of string
           | `Up of string ]
          list -> 'a -> 'd -> int
      end
  end
#

Comments (0)

You don't have permission to comment on this page.