From: Leo White <lpw25@cam.ac.uk>
To: "Raphael 'kena' Poss" <r.poss@uva.nl>
Cc: caml-list@inria.fr
Subject: Re: [Caml-list] Polymorphic module type constraints
Date: Thu, 03 Apr 2014 17:52:20 +0100 [thread overview]
Message-ID: <y2aob0iwe2j.fsf@kingston.cl.cam.ac.uk> (raw)
In-Reply-To: <DC1E40E6-C62A-47BB-9CFF-62B5E45195DB@uva.nl>
> To show what I want, here is an example that "works fine" but uses regular types:
>
> module type Eq = sig
> type t
> val (=) : t -> t -> bool
> val (<>) : t -> t -> bool
> end
>
> let makeEq (type a) eq =
> let module S = struct
> type t = a
> let (=) = eq
> let (<>) x y = not (x = y)
> end
> in (module S : Eq with type t = a)
>
> (* val eq1: int -> int -> bool *)
> let eq1 a b = (a mod 3) = (b mod 3)
> module Eq1 = (val makeEq eq1)
>
> Here, I encounter the first issue:
>
> (* val eq2: 'a option -> 'a option -> bool *)
> let eq2 a b = match (a, b) with
> | (None, None) -> true
> | (Some x, Some y) -> x = y
> | _ -> false
>
> module Eq2 = (val makeEq ~eq2)
>
> =>
> Error: The type of this packed module contains variables:
> (module Eq with type t = 'a option)
>
> Is there any way to generalize?
It is not clear what module type you expect `Eq2` to have. The following
type does not make any sense:
sig
type t = 'a option
val (=) : t -> t -> bool
val (<>) : t -> t -> bool
end
because the type variable `'a` is not bound. On the other hand:
sig
type 'a t = 'a option
val (=) : 'a t -> 'a t -> bool
val (<>) : 'a t -> 'a t -> bool
end
is not an instance of `Eq` which is the module type of `makeEq eq1`.
In addition `makeEq eq2` has type `(module Eq with type t =
'_a option)`. Note that the type variable '_a is weakly
polymorphic. This is due to the value restriction: `makeEq` may create
some state which is used in its returned module, meaning it cannot
safely be polymorphic.
> My first try:
>
> let makeMappable1 (type s) (module O : Poly with type t = s) map =
> let module S : Mappable with type 'a t = 'a O.t = struct
> include O
> let map : ('a -> 'b) -> 'a t -> 'b t = map
> end
> in (module S)
>
> =>
> Error: In this `with' constraint, the new definition of t
> does not match its original definition in the constrained signature:
> Type declarations do not match: type t is not included in type 'a t
>
> Ok, fair enough:
>
> let makeMappable2 (type s) (module O : Poly with type 'a t = s) map =
> let module S : Mappable with type 'a t = 'a O.t = ...
>
> =>
> Error: Syntax error: module-expr expected. (location: with type ... on first line)
>
> So, I try to fix this with:
>
> let makeMappable3 (module O : Poly) map =
> let module S : Mappable with type 'a t = 'a O.t = struct
> include O
> let map : ('a -> 'b) -> 'a t -> 'b t = map
> end
> in (module S)
>
> =>
> Error: This expression has type ('a -> 'b) -> 'a O.t -> 'b t
> but an expression was expected of type ('a -> 'b) -> 'a O.t -> 'b t
> The type constructor O.t would escape its scope
>
> Any suggestion as to how to define makeMappable?
The function `makeMappable` that you are trying to write is polymorphic
in a type constructor (`O.t`), in other words it is higher-kinded. The
core OCaml type system does not support higher-kinded polymorphism, and
the traditional solution is to use functors:
module MakeMappable (O : Poly) (M : Mappable with type 'a t := 'a O.t) = struct
type 'a t = 'a O.t
let map = M.map
end
Of course, this particular functor is pretty redundent.
(A possible alternative is to use the higher library with the approach
described in: https://github.com/ocamllabs/higher/raw/paper/higher.pdf)
Regards,
Leo
prev parent reply other threads:[~2014-04-03 16:52 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-03-21 7:31 Raphael 'kena' Poss
2014-04-03 16:52 ` Leo White [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=y2aob0iwe2j.fsf@kingston.cl.cam.ac.uk \
--to=lpw25@cam.ac.uk \
--cc=caml-list@inria.fr \
--cc=r.poss@uva.nl \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox