caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* [Caml-list] Polymorphic module type constraints
@ 2014-03-21  7:31 Raphael 'kena' Poss
  2014-04-03 16:52 ` Leo White
  0 siblings, 1 reply; 2+ messages in thread
From: Raphael 'kena' Poss @ 2014-03-21  7:31 UTC (permalink / raw)
  To: caml-list

Hi all,

I am trying to take advantage of OCaml locally abstract types to constrain a functor. I want to use this to support the creation of modules from user-provided functions and some defaults. I encounter two issues with polymorphic types, which I am unable to solve. Maybe you will have some suggestions?

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?



Now, the other issue is when the signature explicitly declares a polymorphic type:

  module type Poly = sig
    type 'a t
  end
  module type Mappable = sig
    type 'a t                                                                                                                                              
    val map : ('a -> 'b) -> 'a t -> 'b t
  end

So far so good; but how to define makeMappable function, that takes a map function and Poly module and defines a Mappable instance from them?

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?

Thanks in advance,


-- 
Raphael 'kena' Poss · r.poss@uva.nl
http://staff.science.uva.nl/~poss/








^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [Caml-list] Polymorphic module type constraints
  2014-03-21  7:31 [Caml-list] Polymorphic module type constraints Raphael 'kena' Poss
@ 2014-04-03 16:52 ` Leo White
  0 siblings, 0 replies; 2+ messages in thread
From: Leo White @ 2014-04-03 16:52 UTC (permalink / raw)
  To: Raphael 'kena' Poss; +Cc: caml-list

> 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

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2014-04-03 16:52 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-03-21  7:31 [Caml-list] Polymorphic module type constraints Raphael 'kena' Poss
2014-04-03 16:52 ` Leo White

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).