Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 112 lines (93 sloc) 4.548 kB
fccc685 Initial open-source release
MLstate authored
1 (*
2 Copyright © 2011 MLstate
3
4 This file is part of OPA.
5
6 OPA is free software: you can redistribute it and/or modify it under the
7 terms of the GNU Affero General Public License, version 3, as published by
8 the Free Software Foundation.
9
10 OPA is distributed in the hope that it will be useful, but WITHOUT ANY
11 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
13 more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with OPA. If not, see <http://www.gnu.org/licenses/>.
17 *)
18 (*
19 @author Louis Gesbert
20 **)
21
22 (** This module contains functions and types that are helpful when programming
23 in Continuation Passing Style. Included are the Duck-Style-Cps© guidelines,
24 for easier and more readable CPS code. *)
25
26 (** This type is convenient for more readable cps types:
27 for example, [List.map] has type [('a -> 'b) -> 'a list -> 'b list],
28 which in CPS becomes
29 [('a -> ('b -> unit) -> unit) -> 'a list -> ('b list -> unit) -> unit]
30 Using [Cps.t], one can write it:
31 [('a -> 'b Cps.t) -> 'a list -> 'b list Cps.t]
32 *)
33 type 'a t = ('a -> unit) -> unit
34
35 (** Open this module for duck-style cps-programming©.
36
37 The style is based on two operators, the Duck [@>] for "application of function
38 to continuation" ("apply"), and the Pipe [|>] for "application of continuation
39 to value" ("return"). It has the nice duality that [f x |> k] and [f x @> k] are
40 to equivalent expressions for [f] resp. in non-cps and in cps. This makes style
41 consistent even though we always use a mixed cps/non-cps style.
42
43 The convention is as follows:
44 - These operators should only be used for continuation application
45 - Application of a function to its continuation must be written [@>]
46 - Application of a continuation to a value (eg [return]) must be written with [|>]
47 - when your code is multiline, always put line breaks just before [@>]. This
48 gives a very readable indentation. Put them after [fun ... ->] as well if
49 it's not enough.
50 - [@>] is associative right, with a priority lower than function
51 application, which allows to remove a {b lot} of parentheses. It also allows
52 to write chains of operations without indentation: {[
53 let f x k =
54 cps_function_one x
55 @> (fun k y -> cps_function_two y @> k)
56 @> (fun k z -> cps_function_three z @> k)
57 @> k
58 ]}
59 which is equivalent to: {[
60 let f x =
61 let y = noncps_function_one x in
62 let z = noncps_function_two y in
63 let a = noncps_function_three z in
64 a
65 ]}
66
67 Remark: a specialised module exists in QmlCpsServerLib for the manipulation of
68 run-time continuations (by opposition to ocaml functions).
69
70 Remark: by convention, all CPS functions take their continuation as last
71 parameter (except for the inline functions for composition, as in the example
72 above). When you write a function that {b actually} works on the continuation
73 (eg. does some transformation to it), take it as first parameter, so that there
74 is no ambiguity.
75 *)
76 module Ops : sig
77 val (|>): 'a -> ('a -> unit) -> unit (** More interestingly written ['a -> 'a t] *)
78 val (@>): 'a t -> ('a -> unit) -> unit (** More interestingly written ['a t -> 'a t] :D *)
79 end
80
81 (** A few of the most common functions on lists, in CPS *)
82 module List : sig
83 val map : ('a -> 'b t) -> 'a list -> 'b list t
84 (** While coding a cps-fold based on List.fold is a fun exercise, it's less efficient. *)
85 val fold : ('acc -> 'a -> 'acc t) -> 'acc -> 'a list -> 'acc t
86 end
87
88 module Option : sig
89 val map : ('a -> 'b t) -> 'a option -> 'b option t
90 end
91
92 module Lazy : sig
93 (** A lazy cps value will be evaluted once time by the first
94 [eval_lazy]. *)
95 type 'a t
96
97 (** [make_lazy push cps] Create an ['a] lazy [cps] value will be
98 evaluated only once at the first call of [eval_lazy t k]. *)
99 val make : ((unit -> unit) -> unit) -> (('a -> unit) -> unit) -> 'a t
100
101 (** [force lazy_cps k] Eval [lazy_cps] value and call [k]
102 continuation with ['a] computed value. *)
103 val force : 'a t -> ('a -> unit) -> unit
104
105 (** Access to the cps lazy state. Returns [None] if the cps lazy value
106 is not evaluated, else return the evaluated value.*)
107 val get_state : 'a t -> 'a option
108
109 (** As Ocaml's [Lazy.lazy_from_val]: returns an already-forced suspension *)
110 val lazy_from_val : 'a -> 'a t
111 end
Something went wrong with that request. Please try again.