*

- Introduction
- Translating types
- Calling OCaml from CDuce
- Calling CDuce from OCaml
- How to compile and link
- Calling OCaml from the toplevel
- Examples

Interfacing CDuce with OCaml

CDuce: documentation: User's manual: Interfacing CDuce with OCaml XML Schema sample documents Quick reference

Introduction

This page describes the CDuce/OCaml interface. This interface allows the programmer to:

- call OCaml functions from a CDuce module;
- export a CDuce model as an OCaml module, by giving it an explicit OCaml signature.

The intended usages for the interface are:

- Reuse existing OCaml libraries, such as database, network, GUI, data structures;
- Use CDuce as an XML layer (input/output/transformation) for OCaml projects;
- Develop fully mixed OCaml/CDuce projects.

To see how to build CDuce with support for the OCaml interface, see the INSTALL file from the CDuce distribution.

Translating types

The heart of the interface is a mapping from OCaml types to CDuce types. An OCaml type `t` is translated to a CDuce type `T(t)`, which is meant to be isomorphic to `t`: there is a canonical function `t` → `T(t)` from OCaml values of type `t` to CDuce values of type `T(t)`, and another canonical function `T(t)` → `t`.

- Basic OCaml types `char`, `int`, `string`, `unit` are translated respectively to `Byte = '\0;'--'\255;'`, `-1073741824 -- 1073741823`, `Latin1 = [ Byte* ]`, `[] = `nil`.
- Tuple types `t1 * ... * tn` are translated to nested CDuce product types `(T(t1),(...,T(tn))...)`. A function type `t -> s` is translated to `T(t) -> T(s)`. Labels on the argument of the arrow are discarded.
- A list type `t list` is translated to an homogeneous sequence type `[ T(t)* ]`. An array type `t array` has the same translation.
- A option type `t option` is translated to the type `[ T(t)? ]`.
- A variant type with a declaration `A1 of t1 | ... | An of tn` is translated to a type `(`A1,T(t1)) | ... | (`An,T(tn))`. If a constructor `Ai` has no argument, the resulting term is ``Ai`, not `(`Ai,[])`. Polymorphic variant types are treated similarly.
- A record type with a declaration `{ l1 : t1; ...; ln : tn }` is translated to a closed record type `{ l1 = T(t1); ... ; ln = T(tn) }`. Mutable fields are just copied.
- Private variant and record types are treated correctly: the interface never tries to generate OCaml values of these types, but it will happily translate them to CDuce values.
- A reference type `t ref` is translated to the CDuce reference type `ref T(t)`. When converting a Caml reference to CDuce, the operation (set,get) on the resulting reference refers to the original reference. However, when converting a CDuce reference to OCaml, the content of the reference is fetched (set), and a fresh OCaml reference is created (copy semantics).
- The type `Cduce_lib.Value.t` is translated to the CDuce type `Any`. The corresponding translation functions are the identity. This can be used to avoid multiple copies when translating a complex value back and forth between CDuce and OCaml. The type `Cduce_lib.Encodings.Utf8.t` is translated to the CDuce type `String`. The type `Big_int.big_int` is translated to the CDuce type `Int`.
- A monomorphic abstract type `t` is translated to the CDuce type `!t`. This type just acts as a container for values of the abstract type. CDuce never produces a value of this type, and it cannot inspect the content of such a value (apart from checking its type).

The canonical translation is summarized in the following box:

OCaml type `t` | CDuce type `T(t)`
--- | ---
`char` | `Byte = '\0;'--'\255;'`
`int` | `-1073741824 -- 1073741823`
`string` | `Latin1 = [ Byte* ]`
`unit` | `[] = `nil`
`bool` | `Bool = `true | `false`
`t1 * ... * tn` | `(T(t1),(...,T(tn))...)`
`t -> s` | `T(t) -> T(s)`
`t list` | `[ T(t)* ]`
`t array` | `[ T(t)* ]`
`t option` | `[ T(t)? ]`
`A of t | B of s | C` | `(`A, T(t)) | (`B, T(s)) | `C`
`[ `A of t | `B of s | `C ]` | `(`A, T(t)) | (`B, T(s)) | `C`
`{ x : t; y : s }` | `{ x = T(t); y = T(s) }`
`t ref` | `ref T(t)`
`Cduce_lib.Value.t` | `Any`
`Cduce_lib.Encodings.Utf8.t` | `String`
`Big_int.big_int` | `Int`

Only monomorphic types are handled by the interface. It is allowed to use polymorphic constructors as an intermediate, as long as the final type to be translated is monomorphic. Recursive types, including unguarded ones (option `-rectypes` of the OCaml compiler) are accepted. In the following example:

    type 'a t = A of int | B of 'a t
    type s = int t

    type 'a u = A of ('a * 'a) u | B
    type v = int u

the type `s` can be translated, but the type `v` can't, because its infinite unfolding is not a regular type.

OCaml object types are not supported.

Note that values are copied in depth (until reaching an abstract type, a function types, etc...). In particular, translating an OCaml cyclic values to CDuce will not terminate (well, with a stack overflow!).

Calling OCaml from CDuce

If an OCaml value has a type that can be translated, it is possible to use it from CDuce (see the How to compile and link section for more details).

In a CDuce module, you can write `M.f` to denote the result of translating the OCaml value `M.f` to CDuce.

If the value you want to use has a polymorphic type, you can make the translation work by explicitly instantiating its type variables with CDuce types. The syntax is `M.f with { t1 ... tn }` where the `ti` are CDuce types. The type variables are listed in the order they appear in a left-to-right reading of the OCaml type. Example:

    let listmap = List.map with { Int String }

will return a function of type `(Int -> String) -> ([Int*] -> [String*])`

Calling CDuce from OCaml

We have seen in the section above how OCaml values can be used from a CDuce module. It is also possible to use CDuce values from OCaml. To do so, you must give an OCaml interface (.mli) for the CDuce module (.cdo). The interface can define arbitrary types, and declare monomorphic values. These values must be defined in the CDuce module with a compatible type (subtype of the translation).

As an example, suppose you have this CDuce module (foo.cd):

    type s = (`A,int) | `B
    let double (x : Latin1) : Latin1 = x @ x
    let dump (x : s) : Latin1 = string_of x

You can define an OCaml interface for it (foo.mli):

    type t = A of int | B
    val double: string -> string
    val dump: t -> string

When the foo.cdo module is compiled, CDuce will look for the foo.cmi compiled interface (hence, you must first compile it yourself with OCaml), and generate stub code, so as to define an OCaml module `Foo` with the given interface. This module can then be linked together with other "regular" OCaml modules, and used from them.

Notes:

- It is not mandatory to export all the values of the CDuce module in the OCaml interface.
- The types defined in the interface cannot (currently) be used within the CDuce module.

How to compile and link

Here is the protocol to compile a single CDuce module:

- Create a `.cmi` from your OCaml file with `ocamlc -c foo.mli`.
- Compile your CDuce file `cduce --compile foo.cd`. This command will create a CDuce bytecode file `foo.cdo`, which also contains the OCaml glue code to export CDuce values as OCaml ones, and to bind OCaml values used within the CDuce module.
- Compile the OCaml glue code `ocamlfind ocamlc -c -package cduce -pp "cduce --mlstub" -impl foo.cdo`. The `--mlstub` option tells CDuce to extract the OCaml glue code from the CDuce bytecode file. You can directly run `cduce --mlstub` on a `.cdo` file to better understand how the OCaml/CDuce interface works.

Note: The command `cduce --mlstub` must find the `.cmi` file for the unit. You need to add an `-I` flag if this file is not in the current directory (and additional flags if other `.cmi` are referenced).

You can then link the resulting OCaml module, maybe with other modules (either regular ones, or wrapping a CDuce module): `ocamlfind ocamlc -o ... -package cduce -linkpkg foo.cmo ...`. The content of `foo.cdo` is wrapped inside the OCaml glue code; as a consequence, this file is not needed at runtime.

Everything works mutatis mutandis with the native OCaml compiler ocamlopt.

You might need to pass extra `-I` flags to CDuce so that it could find the referenced `.cmi` files.

It is possible to run a CDuce module with `cduce --run foo.cdo`, but only if it doesn't use OCaml values. If it does use OCaml values, you need to produce a custom version of `cduce` (to compile and run), see: Calling OCaml from the toplevel section.

Calling OCaml from the toplevel

The tool `cduce_mktop` creates custom versions of the CDuce toplevel/compiler/interpreter with built-in support for some OCaml modules / functions.

    cduce_mktop [-I path | -p package | -l unit ... | -byte ] [target] [primitive file]

The `target` argument is the file name of the resulting toplevel. The `primitive file` argument points to a file whose contents specify a set of built-in OCaml values to be embedded in the toplevel. Each line must either be a qualified value (like `List.map`) or the name of an OCaml unit (like `List`). Empty lines and lines starting with a sharp character are ignored.

The `-byte` flag forces the creation of the bytecode version of the toplevel (by defaut, the toplevel is produced with ocamlopt).

The leading `-I` options enrich the search path for OCaml units. The `-p` options serves a similar purpose; their arguments are findlib package names. All these paths are included in the produced toplevel. The `-l` options give the OCaml units to be linked in (e.g. `x.cmx` or `x.cmxa`)(the `-p` option automatically include the units).

In a custom toplevel, the directive `#builtins` prints the name of embedded OCaml values.

Examples

Getting the value of an environment variable

    let home = Sys.getenv "home";;

Ejecting your CD with CDuce

This example demonstrates how to use OCamlSDL library.

    Sdl.init `None [ `EVERYTHING ];;
    let cd = Sdlcdrom.cd_open 0;;
    Sdlcdrom.cd_eject cd;;

If you put these lines in a file `cdsdl.cd`, you can compile and link it with:

    cduce --compile cdsdl.cd -I `ocamlfind query ocamlsdl`
    ocamlfind ocamlc -o cdsdl -pp "cduce --mlstub" -impl cdsdl.cdo   \
      -package cduce,ocamlsdl -linkpkg

Accessing MySQL

This example demonstrates how to use ocaml-mysql library.

    let db = Mysql.connect Mysql.defaults;;

    match Mysql.list_dbs db `None [] with
     | (`Some,l) -> print [ 'Databases: ' !(string_of l) '\n' ]
     | `None -> [];;

    print [
      'Client info: ' !(Mysql.client_info []) '\n'
      'Host info: ' !(Mysql.host_info db) '\n'
      'Server info: ' !(Mysql.server_info db) '\n'
      'Proto info: ' !(string_of (Mysql.proto_info db)) '\n'
    ];;

If you put these lines in a file `cdmysql.cd`, you can compile and link it with:

    cduce --compile cdmysql.cd -I `ocamlfind query mysql`
    ocamlfind ocamlc -o cdmysql -pp "cduce --mlstub" -impl cdmysql.cdo   \
      -package cduce,mysql -linkpkg

Evaluating CDuce expressions

This example demonstrates how to dynamically compile and evaluate CDuce programs contained in a string.

    let pr = Cduce_lib.Value.print_utf8

    try
     let l = Cduce_lib.Cduce.eval
      "let fun f (x : Int) : Int = x + 1;;
       let fun g (x : Int) : Int = 2 * x;;
       let x = getenv ['HOME'];;
       f;; g;;
       let a = g (f 10);;
      "
     in
     let _ = map l with
      | ([id], v) ->
    	pr [ !(string_of id) ' = ' !(string_of v) '\n' ]
      | ([], f & (Int -> Int)) ->
            pr [ !(string_of (f 100)) '\n' ]
      | ([], v) ->
    	pr [ !(string_of v) '\n' ]
     in []
    with (exn & Latin1) ->
      print [ 'Exception: ' !exn  '\n' ]

If you put these lines in a file `eval.cd`, you can compile and link it with:

    cduce --compile eval.cd -I `ocamlfind query cduce`
    ocamlfind ocamlc -o eval -pp "cduce --mlstub" -impl eval.cdo -package cduce -linkpkg

Use CDuce to compute the factorial on big integers

    (* File cdnum.mli: *)

    val fact: Big_int.big_int -> Big_int.big_int

    (* File cdnum.cd: *)

    let aux ((Int,Int) -> Int)
     | (x, 0 | 1) -> x
     | (x, n) -> aux (x * n, n - 1)

    let fact (x : Int) : Int = aux (Big_int.unit_big_int, x)
      (* Could write 1 instead of Big_int.unit_big_int. Just for fun. *)

Site map

CDuce: documentation: User's manual: Interfacing CDuce with OCaml XML Schema sample documents Quick reference