foreign-ocaml-0.1.0.0: Haskell Foreign Function Interface (FFI) for OCaml

Copyright(c) Alessandro Bruni 2014
LicenseGPL-2
Maintaineralbr@dtu.dk
Safe HaskellNone
LanguageHaskell98

Foreign.OCaml

Description

Haskell Foreign Function Interface (FFI) for OCaml. Allows integrating OCaml code into Haskell programs: right now the interface is still pretty rough, and there are probably terrible memory holes that we need to deal with, consider it as a proof of concept.

It offers:

  • calling OCaml functions from Haskell;
  • serialization and deserialization of OCaml datatypes, including unit, bool, int, double, string, lists, tuples and options;
  • limited automatic suppport for serializing algebraic data types, works when there are no type variables (helper functions are provided for converting between the two representations, so custom serializations can be built)
  • strict and lazy evaluation, support for side effects

Current limitations:

  • does not support passing higher order functions to OCaml (Haskell function serialization is not supported)
  • tuple serialization limited to tuples of 2 to 5 arguments
  • no handling of garbage collection, so your program might explode

Synopsis

Documentation

caml_startup :: [String] -> IO ()

Startup for the OCaml runtime: call this function before using any other function in this module. The list of arguments is fed to the OCaml runtime. For example:

main = do
  args <- getArgs
  caml_startup args
  -- ..rest of the program..

class Marshal t where

Marshal provides functions for transforming a Haskell representation of data into OCaml and viceversa. Default implementations are given for all basic types: Unit, Bool, Int, Float, Double, String; and dependent declarations allow to construct Marshal implementations for lists, tuples and applicative types. Note that for applicative types the marshal function is not implemented, so it is not (yet) possible to pass higher order values.

Methods

marshal :: t -> Value

marshal takes a Haskell value of type t and produces an opaque OCaml value.

unmarshal :: Value -> t

unmarshal takes an OCaml value and returns its deserialization into a Haskell data type

Instances

Marshal Bool

Converts Bool into bool

Marshal Double

Converts an Haskell Double into an OCaml float, which is a double precision floating point value.

Marshal Float

Converts an Haskell Float into an OCaml float, which is a double precision floating point value.

Marshal Int

Represents the int datatype in OCaml. Be aware of the difference in representation between the OCaml and the Haskell datatypes: OCaml's int datatype is a 31 bit signed integer, while Haskell's Int is a 32 bit signed integer, hence the representable ranges vary.

Marshal String

Converts an Haskell String into an OCaml string. Note that while the first is just an alias for [Char], string is a native datatype. Needs the extensions -XFlexibleInstances and -XOverlappingInstances in order to work properly.

Marshal ()

Converts () into unit

Marshal a => Marshal [a]

Converts an Haskell list into an OCaml list.

Marshal a => Marshal (IO a)

Use the IO monad to mark those functions that produce side effects to the system. The IO monad also enforces strict evaluation, hence the call is executed at the point where the function is called.

Marshal a => Marshal (Maybe a)

Converts the Maybe monad to the corresponding OCaml datatype.

Marshal a => Marshal ([Value] -> a)

Allows calling the C function caml_callbackN, by passing marshalled arguments in reverse order. It is supposed to be more efficient than the other forms, but is not general, so use it with care.

(Marshal a, Marshal b) => Marshal (a -> b)

Applicative types: allows calling OCaml functions of type a -> b. Please note that marshalling is not supported, hence no functions can be passed as values to OCaml.

(Marshal a, Marshal b, Marshal c) => Marshal (a -> b -> c)

Applicative types: allows calling OCaml functions of type a -> b -> c. Please note that marshalling is not supported, hence no functions can be passed as values to OCaml.

(Marshal a, Marshal b, Marshal c, Marshal d) => Marshal (a -> b -> c -> d)

Applicative types: allows calling OCaml functions of type a -> b -> c -> d. Please note that marshalling is not supported, hence no functions can be passed as values to OCaml.

(Marshal a, Marshal b) => Marshal (a, b)

Converts an Haskell 2-tuple into an OCaml 2-tuple and viceversa

(Marshal a, Marshal b, Marshal c) => Marshal (a, b, c)

Converts an Haskell 3-tuple into an OCaml 3-tuple and viceversa

(Marshal a, Marshal b, Marshal c, Marshal d) => Marshal (a, b, c, d)

Converts an Haskell 4-tuple into an OCaml 4-tuple and viceversa

(Marshal a, Marshal b, Marshal c, Marshal d, Marshal e) => Marshal (a, b, c, d, e)

Converts an Haskell 5-tuple into an OCaml 5-tuple and viceversa

deriveMarshalInstance :: Name -> Q [Dec]

Automatically generate an instance of Marshal given a datatype. If you have an OCaml data type with no type variables and multiple constructors:

type t = C1 of int * string | C2 of t * t | C3

Simply produce a corresponding Haskell data type, then call deriveMarshalInstance to obtain two way conversion between the Haskell and OCaml representations:

data T = C1 Int String | C2 T T | C3
$(deriveMarshalInstance ''T)

type Value = CLong

Opaque datatype that represents an OCaml object.

type Tag = CUInt

Represents tags used in block constructors

register_closure :: Marshal a => String -> a

register_closure returns a closure of type a for any OCaml name that has been registered with:

let _ = Callback.register "f" f

If f is a function of OCaml type int -> int then it can be registered with:

f = register_closure "f" :: Int -> Int

register_closure works with type variables as well, as long as all its instantiations are also instance of Marshal. For example the function linearize that takes a tree and returns a list, with parameter type a:

type 'a tree = Leaf of 'a | Node of 'a tree * 'a tree;;
let rec linearize t = match t with
  | Leaf(x)   -> [x]
  | Node(l,r) -> let ll = linearize l in
                 let lr = linearize r in
                 ll @ lr;;
let _ = Callback.register "linearize" linearize

can be registered as such:

linearize = register_closure "linearize" :: Tree a -> [a]

provided that an implementation of Tree a and Marshal for both Tree a and a exist.

block_constructor :: Tag -> [Value] -> Value

Produces a block constructor, that is, a constructor with arguments. The integer pararmeter is the index of the block constructor, in order of appearance on the declaration of the datatype, counting from 0 and not considering constant constructors.

constant_constructor :: Int -> Value

Produces a constant constructor, that is, a constructor that has no parameters. The integer parameter is the index of the constant constructor, in order of appearance on the declaration of the datatype, counting from 0 and not considering block constructors.

is_block :: Value -> Bool

True if v is a block constructor

is_value :: Value -> Bool

True if v is an atomic value

get_const :: Value -> Int

Returns the index for a constant constructor, inverse of constant_constructor.

get_field :: Value -> Int -> Value

Returns a field in position offset from a block constructor.

get_tag :: Value -> CUChar

Returns the idnex for a block constructor, more or less an inverse of block_constructor, to be used together with get_field