Commit 264d528d authored by Pietro Abate's avatar Pietro Abate
Browse files

[r2004-06-28 15:08:56 by afrisch] Doc

Original author: afrisch
Date: 2004-06-28 15:08:56+00:00
parent b4880b35
......@@ -41,136 +41,194 @@ see the INSTALL file from the CDuce distribution.
<p>
The heart of the interface is a mapping from OCaml types to CDuce
types. An OCaml type <code>t</code> is translated to a CDuce type
<code>T(t)</code>, which is meant to be &rarr; isomorphic to <code>t</code>:
there exist a canonical function <code>t &rarr; T(t)</code>
<code>T(t)</code>, which is meant to be isomorphic to <code>t</code>:
there is a canonical function <code>t</code> &rarr; <code>T(t)</code>
from OCaml values of type <code>t</code> to CDuce values of type
<code>T(t)</code>, and another canonical function <code>T(t) &rarr; t</code>.
<code>T(t)</code>, and another canonical function <code>T(t)</code> &rarr; <code>t</code>.
</p>
</box>
<p>
Basic OCaml types <code>char</code>, <code>int</code>, <code>string</code>,
<code>unit</code> are translated respectively to
<code>Byte = '\0;'--'\255;'</code>, <code>-1073741824 --
1073741823</code>, <code>Latin1 = [ Byte* ]</code>, <code>[] = `nil</code>.
</p>
<box title="The interface file" link="interface">
<p>
Tuple types <code>t1 * ... tn</code> are translated to nested CDuce
product types <code>(T(t1),(...,T(tn))...)</code>. A function type
<code>t -> s</code> is translated to <code>T(t) -> T(s)</code>.
</p>
<p>
As you have probably seen CDuce uses regular expression based
pattern-matching. This feature, combined with others, makes CDuce
translation to OCaml a bit hard. That is why you are asked to provide an
OCaml interface file to help the CDuce compiler in producing needed code
to let you call CDuce from your ML programs.
A list type <code>t list</code> is translated to an homogenous
sequence type <code>[ T(t)* ]</code>.
</p>
<p>
This file must contain declarations of all your functions and types you
want to export from CDuce code.
A variant type with a declaration <code>A1 of t1 | ... | An of
tn</code> is translated to a type <code>(`A1,T(t1)) | ... |
(`An,T(tn))</code>. If a constructor <code>Ai</code> has no argument, the resulting
term is <code>`Ai</code>, not <code>(`Ai,[])</code>.
Polymorphic variant types are treated similarly.
</p>
<p>
For example, consider the following CDuce code, written in file <code>foo.cd</code>:
A record type with a declaration <code>{ l1 : t1; ...; ln : tn
}</code> is translated to a closed record type <code>{| l1 = T(t1);
... ; ln = T(tn) |}</code>. Mutable fields are just copied.
</p>
<sample><![CDATA[
type ML_int = -1073741824 -- 1073741823
<p>
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.
</p>
let f ( Int -> ML_int )
x & ML_int -> x
| _ -> raise "Overflow"
]]></sample>
<p>
A reference type <code>t ref</code> is translated to the CDuce
reference type <code>ref T(t)</code>. 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).
</p>
<p>
And now the OCaml code in file, <code>foo.mli</code> (we use the blue color to highlight OCaml code):
The type <code>CDuce_all.Value.t</code> is translated to the CDuce
type <code>Any</code>. 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.
</p>
<sample><![CDATA[
$$val f : int -> int$$
]]></sample>
<p>
A <em>monomorphic</em> abstract type <code>t</code> is translated to
the CDuce type <code>!t</code>. 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).
</p>
<p>
The function declared in foo.mli is the interface between CDuce and OCaml,
you are free to call it from any of your OCaml programs, as in:
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 in monomorphic. Recursive types, including
unguarded ones (option <code>-rectypes</code> of the OCaml compiler)
are accepted. In the following example:
</p>
<sample><![CDATA[
$$let () =
if Foo.$${{f}}$$ 8 <> 8 then failwith "Error"$$
]]></sample>
<sample>
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
</sample>
<p>
Note that there are two rules to respect when creating your interface file:
the type <code>s</code> can be translated, but the type <code>v</code>
can't, because its infinite unfolding is not a regular type.
</p>
<ul>
<li>
Every value defined in your OCaml file (<code>.mli</code>) has to
be defined in your CDuce file. Whereas the opposite is not
necessary: you can have much more (top-level) values in your CDuce file than in
your OCaml interface, only the latter are exported by the module.
</li>
<li>
Every type associated to a CDuce expression by the <code>.mli</code> file
must be <i>compatible</i> with the CDuce type of the expression.
</li>
</ul>
<p>
What does <i>compatible</i> mean? We have defined a canonical translation
<code>T()</code> from OCaml types to CDuce types (see next frame). The
OCaml type declared for a CDuce expression in a <code>.mli</code> is
compatible with the CDuce type of the expression if the latter is a
subtype of the canonical translation of the former.
OCaml object types are not supported.
</p>
</box>
<box title="Calling OCaml from CDuce" link="call_ocaml">
<p>
If an OCaml value has a type that can be translated, it is possible to
use it from CDuce (see the <a href="#link">How to compile and link</a> section for
more details).
</p>
<p>
For instance, the previous example respects this rule since the
canonical translation of <code>int</code> is <code>ML_int</code>
that is a subtype of <code>Int</code>. Therefore the type <code>int
-> int</code> whose canonical translation is <code>ML_int ->
ML_int</code>, is <i>compatible</i> with the CDuce type of
<code>f : Int -> ML_int</code>. Instead, since
the canonical translation of <code>int -> int</code> is not a
supertype of <code>Int -> Int</code>, then if we had used this type
in the definition of the CDuce function it would be rejected by the
compiler.
In the CDuce module, you can write <code>external "M.f"</code>
to denote the result of translating the OCaml value <code>M.f</code>
to CDuce.
</p>
<p>
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 syntaxe is <code>external { "M.f" t1
... tn }</code> where the <code>ti</code> are CDuce types. The type
variables are listed in the order they appear in a left-to-right
reading of the OCaml type. Example:
</p>
<sample>
let listmap = external { "List.map" Int String }
</sample>
<p>
will return a function of type <code>(Int -> String) -> ([Int*] -> [String*])</code>
</p>
</box>
<box title="Translation function" link="trans">
<box title="Calling CDuce from OCaml" link="call_cduce">
<p>
To know if a OCaml type is a subtype of a CDuce one, it is extremely simple,
you just have to follow the translation function, <code>T</code>, given by:
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).
</p>
<sample><![CDATA[
T($$bool$$) = Bool
T($$char$$) = Char
T($$int$$) = -1073741824 -- 1073741823
T($$string$$) = Latin1
T($$unit$$) = []
T($$%%t%%$$ $$*$$ $$%%u%%$$) = ( T($$%%t%%$$) , T($$%%u%%$$) )
T($$%%t%%$$ $$->$$ $$%%u%%$$) = T($$%%t%%$$) -> T($$%%u%%$$)
T($$%%t%%$$ $$|$$ $$%%u%%$$) = T($$%%t%%$$) | T($$%%u%%$$)
T($$%%t%%$$ $$list$$) = [ T($$%%t%%$$)* ]
T($$A$$) = `A
T($$A of$$ $$%%t%%$$) = ( `A, T($$%%t%%$$) )
| { u : T($$%%t%%$$) } if in contravariant (argument) position
T($${ u :$$ $$%%t%%$$ $$}$$) = <
| {| u : T($$%%t%%$$) |} if in covariant (result) position
<p>
As an example, suppose you have this CDuce module (foo.cd):
</p>
<sample>
type s = (`A,int) | `B
let double (x : Latin1) : Latin1 = x @ x
let dump (x : s) : Latin1 = string_of x
</sample>
]]></sample>
<p>
The translation is straightforward so it deserves few remarks. Just notice that
since OCaml records are not extensible then we translate them by strict CDuce
records, but when a record type is specified in a contravariant position we use
the non strict ones as we want to allow to use a CDuce function that can be fed
with a record with lesser fields where an OCaml function for arguments with more
fields is expected.<br/>
Polymorphic variants, polymorphic types, and abstract types cannot be specified (yet).
You can define an OCaml interface for it (foo.mli):
</p>
<sample>
type t = A of int | B
val double: string -> string
val dump: t -> string
</sample>
<p>
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
<code>Foo</code> with the given interface. This module can then be
linked together with other "regular" OCaml modules, and used from them.
</p>
<p>
Notes:
</p>
<ul>
<li>
It is not mandatory to export all the values of the CDuce module in
the OCaml interface.
</li>
<li>
The types defined in the interface cannot (currently) be used
within the CDuce module.
</li>
</ul>
</box>
<box title="How to compile files" link="comp">
<box title="How to compile and link" link="link">
<p>
When you have created a good enough interface file, you have to build both
CDuce and OCaml source codes. To do that simply follow those instructions:
Here is the protocol to compile a single CDuce module:
</p>
<ul>
......@@ -180,16 +238,61 @@ CDuce and OCaml source codes. To do that simply follow those instructions:
</li>
<li>
Compile your CDuce file <code>cduce --compile foo.cd</code>. This command
will create a CDuce bytecode file (<code>.cdo</code>) and a OCaml file
(<code>.ml</code>) containing implementation of your declared functions.
will create a CDuce bytecode file <code>foo.cdo</code>, which
also contains the OCaml glue code to export CDuce values as OCaml
ones, and to bind OCaml values used within the CDuce module.
</li>
<li>
Build your final binary but do not forget to link it against
<code>cDuce_all.cma</code> library which contains CDuce interpreter. To
do that, just run
<code><![CDATA[ocamlc <...> cDuce_all.cma <...>]]></code>.
Compile the OCaml glue code
<code>ocamlfind ocamlc -c -package cduce -pp cdo2ml foo.cdo</code>.
The<code>cdo2ml</code> tool extracts the OCaml glue code from the
CDuce bytecode file.
</li>
</ul>
<p>
You can then link the resulting OCaml module, maybe with other
modules (either regular ones, or wrapping a CDuce module):
<code>ocamlfind ocamlc -o {{...}} -package cduce -linkpkg foo.cmo {{...}}</code>.
When the program is run, the CDuce bytecode file
<code>foo.cdo</code> is looked in the <em>current directory</em>
only, and loaded dynamically (with a checksum test).
</p>
<p>
It might be preferable to include the CDuce bytecode directly into
the OCaml glue code. You can do this by giving <code>cdo2ml</code>
the <code>-static</code> option:
<code>ocamlfind ocamlc -c -package cduce -pp "cdo2ml -static" foo.cdo</code>.
Modules which have been compiled this way don't need the
corresponding <code>.cdo</code> at runtime.
</p>
<p>
If you choose static linking, you have to use a correct ordering
when linking with OCaml. Note that it is possible to mix static and
dynamic linking for various CDuce modules in a same program.
</p>
<p>
Everything works mutatis mutandis with the native OCaml compiler ocamlopt.
</p>
<p>
You might need to pass extra <code>-I</code> flags to CDuce so that
it could find the referenced <code>.cmi</code> files.
</p>
<p>
It is possible to run a CDuce module with <code>cduce --run
foo.cdo</code>, but only if it doesn't use OCaml values (not
currently checked, but please don't try !).
</p>
<p>
Interested users can look at the output of <code>cdo2ml</code> to
better understand how the interface works.
</p>
</box>
</page>
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment