package functoria

  1. Overview
  2. Docs

The Functoria DSL.

The Functoria DSL allows users to describe how to create portable and flexible applications. It allows to pass application parameters easily using command-line arguments either at configure-time or at runtime.

Users of the Functoria DSL composes their application by defining a list of module implementations, specify the command-line Keys that are required and combine all of them together using applicative operators.

The DSL expression is then compiled into an application builder, which will, once evaluated, produced the final portable and flexible application.

Combinators

type _ typ =
  1. | Type : 'a -> 'a typ
  2. | Function : 'b typ * 'c typ -> ('b -> 'c) typ

The type for values representing module types.

val typ : 'a -> 'a typ

type t is a value representing the module type t.

val (@->) : 'a typ -> 'b typ -> ('a -> 'b) typ

Construct a functor type from a type and an existing functor type. This corresponds to prepending a parameter to the list of functor parameters. For example:

kv_ro @-> ip @-> kv_ro 

This describes a functor type that accepts two arguments -- a kv_ro and an ip device -- and returns a kv_ro.

type job

Type for job values.

val job : job typ

job is the signature for user's application main module.

type 'a impl

The type for values representing module implementations.

val ($) : ('a -> 'b) impl -> 'a impl -> 'b impl

m $ a applies the functor m to the module a.

type abstract_impl =
  1. | Abstract : _ impl -> abstract_impl

The type for abstract implementations.

val abstract : _ impl -> abstract_impl

abstract t is t but with its type variable abstracted. Useful for dependencies.

Keys

type key = Functoria_key.t

The type for command-line keys. See Functoria_key.t.

type context = Functoria_key.context

The type for keys' parsing context. See Functoria_key.context.

type 'a value = 'a Functoria_key.value

The type for values parsed from the command-line. See Functoria_key.value.

val if_impl : bool value -> 'a impl -> 'a impl -> 'a impl

if_impl v impl1 impl2 is impl1 if v is resolved to true and impl2 otherwise.

val match_impl : 'b value -> default:'a impl -> ('b * 'a impl) list -> 'a impl

match_impl v cases ~default chooses the implementation amongst cases by matching the v's value. default is chosen if no value matches.

module type KEY = module type of Functoria_key with type 'a Arg.converter = 'a Functoria_key.Arg.converter and type 'a Arg.t = 'a Functoria_key.Arg.t and type Arg.info = Functoria_key.Arg.info and type 'a value = 'a Functoria_key.value and type 'a key = 'a Functoria_key.key and type t = Functoria_key.t and type Set.t = Functoria_key.Set.t and type 'a Alias.t = 'a Functoria_key.Alias.t and type context = Functoria_key.context

The signature for run-time and configure-time command-line keys.

Package dependencies

For specifying opam package dependencies, the type package is used. It consists of the opam package name, the ocamlfind names, and optional lower and upper bounds. The version constraints are merged with other modules.

type package = private {
  1. opam : string;
  2. build : bool;
  3. ocamlfind : Astring.String.Set.t;
  4. min : string option;
  5. max : string option;
}

The type of a package

val package : ?build:bool -> ?sublibs:string list -> ?ocamlfind:string list -> ?min:string -> ?max:string -> string -> package

package ~build ~sublibs ~ocamlfind ~min ~max opam is a package. Build indicates a build-time dependency only, defaults to false. The ocamlfind name is by default the same as opam, you can specify ~sublibs to add additional sublibraries (e.g. ~sublibs:["mirage"] "foo" will result in the findlib names ["foo"; "foo.mirage"] . In case the findlib name is disjoint (or empty), use ~ocamlfind. Specifying both ~ocamlfind and ~sublibs leads to an invalid argument. Version constraints are given as min (inclusive) and max (exclusive).

Application Builder

Values of type impl are tied to concrete module implementation with the foreign construct. Module implementations of type job can then be registered into an application builder. The builder is in charge if parsing the command-line arguments and of generating code for the final application. See Functoria_app for details.

val foreign : ?packages:package list -> ?keys:key list -> ?deps:abstract_impl list -> string -> 'a typ -> 'a impl

foreign name typ is the module name, having the module type typ.

  • If packages is set, then the given packages are installed before compiling the current application.
  • If keys is set, use the given keys to parse at configure and runtime the command-line arguments before calling name.connect.
  • If deps is set, the given list of abstract implementations is added as data-dependencies: they will be initialized before calling name.connect.

For a more flexible definition of packages, or for a custom configuration step, see the configurable class type and the foreign class.

module Info : sig ... end

Information about the final application.

class type 'ty configurable = object ... end

Signature for configurable module implementations. A configurable is a module implementation which contains a runtime state which can be set either at configuration time (by the application builder) or at runtime, using command-line arguments.

val impl : 'a configurable -> 'a impl

impl c is the implementation of the configurable c.

class base_configurable : object ... end

base_configurable pre-defining many methods from the configurable class. To be used as follow:

class 'a foreign : ?packages:package list -> ?keys:key list -> ?deps:abstract_impl list -> string -> 'a typ -> 'a configurable

This class can be inherited to define a configurable with an API similar to foreign.

Sharing

val hash : 'a impl -> int

hash is the hash function on implementations. FIXME(samoht) expand on how it works.

val equal : 'a impl -> 'a impl -> bool

equal is the equality over implementations.

module ImplTbl : Hashtbl.S with type key = abstract_impl

Hashtbl of implementations.