package yocaml

  1. Overview
  2. Docs

An overlay on expression and effect performance.

Currently (OCaml 5.2.x), the definition and interpretation of effects is a feature dedicated to implementing concurrent primitives for OCaml, for example: the Domain API. However, the effects type system has not yet been implemented, so the use of effects and handlers is still experimental.

In YOCaml 1.0.0, effects were abstracted using a Freer Monad, described in the Preface. However, since OCaml 5, it has been possible to describe effects, in order to be able to colour the functions which propagate effects, we use an IO Monad. This allows us to distinguish pure functions from impure functions, while allowing the interpretation, a posteriori of effects, allowing specialisation via a Runtime to ensure the versatility of YOCaml. The trade-off is that you can't really take advantage of the direct style, but the presence of binding operators makes this loss fairly slight.

The Eff Monad

The Eff Monad is an implementation of IO, which produces functions that propagate effects. It is used to distinguish between pure and impure functions.

type 'a t

A type describing an impure normal form. A function from 'a -> 'b should be pure, and a function of 'a -> 'b Eff.t should be impure and, in retrospect, be interpreted by an effect handler.

val return : 'a -> 'a t

return x lift x into an impure context.

val bind : ('a -> 'b t) -> 'a t -> 'b t

bind f x gives the result of the computation x to the function f.

val map : ('a -> 'b) -> 'a t -> 'b t

map f x mapping from 'a t to 'b t.

val join : 'a t t -> 'a t

join x remove one level of monadic structure, projecting its bound argument into the outer level.

val compose : ('a -> 'b t) -> ('b -> 'c t) -> 'a -> 'c t

compose f g is left to right composition of Kleisli Arrows of f . g.

val rcompose : ('b -> 'c t) -> ('a -> 'b t) -> 'a -> 'c t

rcompose f g is the right to left composition of Kleisli Arrows of g . f.

val apply : ('a -> 'b) t -> 'a t -> 'b t

apply f x apply f to x.

val zip : 'a t -> 'b t -> ('a * 'b) t

zip x y is the monoidal product of x and y.

val replace : 'a -> 'b t -> 'a t

replace x e replace the value of e by x.

val void : 'a t -> unit t

void e replace the value of e by unit.

val select : ('a, 'b) Stdlib.Either.t t -> ('a -> 'b) t -> 'b t

select e f apply f if e is Left. It allow to skip effect using Right.

val branch : ('a, 'b) Stdlib.Either.t t -> ('a -> 'c) t -> ('b -> 'c) t -> 'c t

branch x f g if x is Left, it performs f, otherwise it performs g.

val map2 : ('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t

Lift a 2-ary function.

val map3 : ('a -> 'b -> 'c -> 'd) -> 'a t -> 'b t -> 'c t -> 'd t

Lift a 3-ary function.

val map4 : ('a -> 'b -> 'c -> 'd -> 'e) -> 'a t -> 'b t -> 'c t -> 'd t -> 'e t

Lift a 4-ary function.

val map5 : ('a -> 'b -> 'c -> 'd -> 'e -> 'f) -> 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> 'f t

Lift a 5-ary function.

val map6 : ('a -> 'b -> 'c -> 'd -> 'e -> 'f -> 'g) -> 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> 'f t -> 'g t

Lift a 6-ary function.

val map7 : ('a -> 'b -> 'c -> 'd -> 'e -> 'f -> 'g -> 'h) -> 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> 'f t -> 'g t -> 'h t

Lift a 7-ary function.

val map8 : ('a -> 'b -> 'c -> 'd -> 'e -> 'f -> 'g -> 'h -> 'i) -> 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> 'f t -> 'g t -> 'h t -> 'i t

Lift a 8-ary function.

Traversable

Enables traversable structures to be traversed on effects.

module List : sig ... end

Infix operators

Comfort infix operators for composing programmes that produce effects.

module Infix : sig ... end
val (<$>) : ('a -> 'b) -> 'a t -> 'b t

f <$> x is map f x.

val (<*>) : ('a -> 'b) t -> 'a t -> 'b t

f <*> x is apply f x.

val (<*?) : ('a, 'b) Stdlib.Either.t t -> ('a -> 'b) t -> 'b t

c <*? f is select c f

val (>>=) : 'a t -> ('a -> 'b t) -> 'b t

m >>= f is bind f m.

val (=<<) : ('a -> 'b t) -> 'a t -> 'b t

f =<< m is bind f m.

val (>|=) : 'a t -> ('a -> 'b) -> 'b t

m >|= f is map f m.

val (=|<) : ('a -> 'b) -> 'a t -> 'b t

f =|< x is map f x.

val (>=>) : ('a -> 'b t) -> ('b -> 'c t) -> 'a -> 'c t

f >=> g is compose f g.

val (<=<) : ('b -> 'c t) -> ('a -> 'b t) -> 'a -> 'c t

f <=< g is rcompose f g.

Bindings operators

Comfort bindings operators for composing programmes that produce effects and get closer to the direct style.

module Syntax : sig ... end
val let+ : 'a t -> ('a -> 'b) -> 'b t

let+ x = e in f x is f <$> x

val and+ : 'a t -> 'b t -> ('a * 'b) t

let+ x = e and+ y = f in g x y is g <$> e <*> f.

val let* : 'a t -> ('a -> 'b t) -> 'b t

let* x = e in f x is e >>= f.

User defined effects

Description of the effects that can be propagated by a YOCaml program. All effects are prefixed with Yocaml_ to avoid conflicts with another program propagating different effects.

Some effects are common (for example those used to log or propagate errors), some are used to act on the original filesystem and uses a parameter `Source and others act on the target and uses a parameter `Target. This makes it possible, for example, to generate in a target different from the source. This is useful, for example, when generating a site in a git repository, which uses a Unix file system as its source and a git repo as its target.

type filesystem = [
  1. | `Source
  2. | `Target
]
type Stdlib.Effect.t +=
  1. | Yocaml_log : ([ `App | `Error | `Warning | `Info | `Debug ] * string) -> unit Stdlib.Effect.t
    (*

    Effect describing the logging of a message attached to a log level. The log level uses the various conventional levels offered, in particular, by the Logs library.

    *)
  2. | Yocaml_failwith : exn -> 'a Stdlib.Effect.t
    (*

    Effect that propagates an error.

    *)
  3. | Yocaml_get_time : unit -> int Stdlib.Effect.t
    (*

    Effect that get the current time.

    *)
  4. | Yocaml_file_exists : filesystem * Path.t -> bool Stdlib.Effect.t
    (*

    Effect that check if a file exists.

    *)
  5. | Yocaml_read_file : filesystem * Path.t -> string Stdlib.Effect.t
    (*

    Effect that read a file from a given filepath.

    *)
  6. | Yocaml_get_mtime : filesystem * Path.t -> int Stdlib.Effect.t
    (*

    Effect that get the modification time of a filepath.

    *)
  7. | Yocaml_hash_content : string -> string Stdlib.Effect.t
    (*

    Effect that hashes a string (used to hide the result of a transformation).

    *)
  8. | Yocaml_write_file : filesystem * Path.t * string -> unit Stdlib.Effect.t
    (*

    Effect which describes the writing of a file

    *)
  9. | Yocaml_is_directory : filesystem * Path.t -> bool Stdlib.Effect.t
    (*

    Effect that returns check if a file is a directory or not.

    *)
  10. | Yocaml_read_dir : filesystem * Path.t -> Path.fragment list Stdlib.Effect.t
    (*

    Effect that returns a list of names of files (and directory) present in the given directory. (Names should be not prefixed by the given path).

    *)
  11. | Yocaml_create_dir : filesystem * Path.t -> unit Stdlib.Effect.t
    (*

    Effect that create a directory.

    *)
  12. | Yocaml_exec_command : string * string list * (int -> bool) -> string Stdlib.Effect.t
    (*

    Effect that perform an Unix call.

    *)
val perform : 'a Stdlib.Effect.t -> 'a t

perform effect colours an effect performance as impure. Replaces Stdlib.Effect.perform x.

val run : ('b, 'c) Stdlib.Effect.Deep.handler -> ('a -> 'b t) -> 'a -> 'c

run handler kleisli_arrow input interprets a Kleisli Arrow (kleisli_arrow) for an effect handler (effect_handler) given as an argument (input).

Exceptions

Exception that can be propagated by the performance of effects.

exception File_not_exists of filesystem * Path.t

Exception raised when a file does not exists.

exception Invalid_path of filesystem * Path.t

Exception raised when a file does not has a basename.

exception File_is_a_directory of filesystem * Path.t

Exception raised when we try to use a directory as a regular file.

exception Directory_is_a_file of filesystem * Path.t

Exception raised when we try to use a file as a directory.

exception Directory_not_exists of filesystem * Path.t

Exception raised when we try to use a directory as a regular file.

exception Provider_error of Required.provider_error

Exception raised when we try to validate an invalid source of metadata.

Helpers for performing effects

Functions producing defined effects.

val log : ?level:[ `App | `Error | `Warning | `Info | `Debug ] -> string -> unit t

log ~level message performs the effect Yocaml_log with a given level and a message.

val logf : ?level:[ `App | `Error | `Warning | `Info | `Debug ] -> ('a, Stdlib.Format.formatter, unit, unit t) Stdlib.format4 -> 'a

logf ~level format performs the effect Yocaml_log with a given level and using a format (like Printf).

val raise : exn -> 'a t

raise exn performs the effect Yocaml_failwith with a given exn.

val failwith : string -> 'a t

failwith message perform the effect Yocaml_failwith with a message that produces an error wrapped into a Failure exception.

val get_time : unit -> int t

get_time () returns the current timestamp.

val exec : ?is_success:(int -> bool) -> string -> ?args:string list -> string t

exec ?is_success prog ?args will executes prog ...args. When is_success is provided, it is called with the exit code to determine whether it indicates success or failure. Without is_success, success requires the process to return an exit code of 0.

printing on standard output is returned.

val exec_cmd : ?is_success:(int -> bool) -> Cmd.t -> string t

exec_cmd ?is_success cmd is exec but relaying on Yocaml.Cmd for describing a shell call.

val file_exists : on:filesystem -> Path.t -> bool t

file_exists ~on path perform the effect Yocaml_file_exists with a given path return true if the file exists, false if not.

val read_file : on:filesystem -> Path.t -> string t

read_file ~on path perform the effect Yocaml_read_file with a given path and try to read it. Perform Yocaml_failwith with File_not_exists if the file does not exists.

val read_file_as_metadata : (module Required.DATA_PROVIDER) -> (module Required.DATA_READABLE with type t = 'a) -> on:filesystem -> Path.t -> 'a t

read_file_as_metadata (module P) (module R) ~on path reads a file located by a path on a data source (on) and validates the content as metadata according to a Yocaml.Required.DATA_PROVIDER, P, using the description provided by R of type Yocaml.Required.DATA_READABLE.

val read_file_with_metadata : (module Required.DATA_PROVIDER) -> (module Required.DATA_READABLE with type t = 'a) -> ?extraction_strategy:Metadata.extraction_strategy -> on:filesystem -> Path.t -> ('a * string) t

read_file_with_metadata (module P) (module R) ?extraction_strategy ~on path reads a file located by a path on a data source (on) and uses an extraction_strategy to separate the metadata from the content and validates the metadata according to a Yocaml.Required.DATA_PROVIDER, P, using the description provided by R of type Yocaml.Required.DATA_READABLE.

val mtime : on:filesystem -> Path.t -> int t

mtime ~on path perform the effect Yocaml_source_get_mtime with a given path and try to get the modification time. Perform Yocaml_failwith with File_not_exists if the file does not exists.

The logic of mtime differs slightly from that of Unix. If a directory is given as an argument, the function will return the largest mtime recursively contained in the directory. This makes it easy to treat directories as dependency sets.

val hash : string -> string t

hash str perform the effect Yocaml_hash_content on a given string.

val create_directory : on:filesystem -> Path.t -> unit t

create_directory ~on target performs recursively Yocaml_create_dir to create a directory.

val write_file : on:filesystem -> Path.t -> string -> unit t

write_file ~on target content performs the effect Yocaml_write_file that should writes a file to a given target. The function use Yocaml.Eff.create_directory for creating intermediate directory in the path.

val is_directory : on:filesystem -> Path.t -> bool t

is_directory ~on target performs the effect Yocaml_is_directory that should check if a file is a directory or not.

val is_file : on:filesystem -> Path.t -> bool t

is_file ~on target performs the effect Yocaml_is_directory and if the file is not a directory, it return true, false otherwise.

val read_directory : on:filesystem -> ?only:[ `Files | `Directories | `Both ] -> ?where:(Path.t -> bool) -> Path.t -> Path.t list t

read_directory ~on ?only ?where path returns a list of children (as a pair of the full path and the name (fragment) of the child) of the given directory, performing Yocaml_read_dir.

val copy_recursive : ?new_name:Path.fragment -> into:Path.t -> Path.t -> unit t

copy_recursive ~on path copy (recursively) a directory or a file into another one.

val get_basename : Path.t -> Path.fragment t

get_basename path returns the basename of a path (and fail if the path has no basename).

OCaml

Innovation. Community. Security.