caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
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

      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;
as well as URLs for NNTP newsgroup(s).