module Generic_util_app:sig
..end
In OCaml parametric types cannot be partially applied: they must be saturated, all parameters must be given for a type expression to be valid. Therefore we cannot easily abstract over polymorphic type constructors and generalise the type of the List.map function:
val map : ('a -> 'b) -> 'a list -> 'b list
Since the syntax doesn't allow to replace list
with a type variable:
val invalidmap : ('a -> 'b) -> 'a 'f -> 'b 'f
The purpose of this module is to be able to write such generalisation using defunctionalisation as described in the article "Lightweight Higher-Kinded Polymorphism" by Jeremy Yallop and Leo White.
The type 'a 'f
is not valid, but we may write ('a,'f) app
,
where the type app
is an extensible gadt.
To each polymorphic type 'a p
, we will associate an abstract type
p'
which is interpreted by the gadt app
such that:
('a, p') app
is isomorphic to 'a p
.
For instance, to represent the list
type constructor,
we define the abstract type list'
:
type list'
and we add a List
constructor to app
:
type (_,_) app += List : 'a list -> ('a, list') app
The generalised map
may then be typed:
val map : ('a -> 'b) -> ('a,'f) app -> ('b,'f) app
Uses of app
in the generic library.
app
is used to define extensible type indexed functions, see
Generic_core_extensible
.
module T:sig
..end
Generic_util_app.T.app
.
type('a, 'b)
t =('a, 'b) T.app
Generic_util
is
opened, and one doesn't want to open App.T
, one can
refer to App.T.app
as App.t
.type
option'
type ('_, '_)
t +=
| |
Option : |
val get_option : ('a, option') t -> 'a option
type
list'
type ('_, '_)
t +=
| |
List : |
val get_list : ('a, list') t -> 'a list
type
array'
type ('_, '_)
t +=
| |
Array : |
val get_array : ('a, array') t -> 'a array
type
id =
| |
ID |
type ('_, '_)
t +=
| |
Id : |
val get_id : ('a, id) t -> 'a
type 't
const =
| |
CONST |
't const
doesn't build useful values, we use
it as a "code" to be interpreted by app
so that ('a, 't
const) app
is isomorphic to 't
.
It would have been better to make 't const
an abstract
type, but it then makes typechecking troublesome for the
constructor Const : 't -> ('a, 't const) app
type ('_, '_)
t +=
| |
Const : |
('a, 'b const) app
is isomorphic to 't
val get_const : ('a, 'b const) t -> 'b
Const
constructortype 'b
exponential =
| |
EXPONENTIAL |
'b exponential
doesn't build useful values,
consider it abstract. We use it as a "code" to be
interpreted by app
so that ('a, 'b exponential) app
is
isomorphic to 'a -> 'b
.type ('_, '_)
t +=
| |
Exponential : |
('a, 'b exponential) app
is isomorphic to 'a -> 'b
.val get_exponential : ('a, 'b exponential) t -> 'a -> 'b
Exponential
constructortype ('f, 'g)
comp =
| |
COMP |
type ('_, '_)
t +=
| |
Comp : |
val get_comp : ('a, ('f, 'g) comp) t ->
(('a, 'f) t, 'g) t