caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Mikhail Mandrykin <mandrykin@ispras.ru>
To: caml-list@inria.fr, Markus Mottl <markus.mottl@gmail.com>
Cc: OCaml List <caml-list@yquem.inria.fr>
Subject: Re: [Caml-list] Late adding of type variable constraints
Date: Wed, 09 Sep 2015 22:28:35 +0300	[thread overview]
Message-ID: <1527892.mlrKSESLQ8@molnar> (raw)
In-Reply-To: <CAP_800re6cPsWFTqovANn7ShfkpCN-eMxOYtC98Us6OpNeXc0g@mail.gmail.com>

On Wednesday, September 09, 2015 10:00:34 AM Markus Mottl wrote:

> In my case I also need to define a type ('a t) such that I can pass it
> on in a functor.  The functor body needs to know that invariants are
> maintained after each mapping: the skeleton, as captured by t, and
> that the same constraints hold for type parameter 'a across mappings.
> Only then can the functor body easily map back and forth between
> various encodings of the type parameters while maintaining the
> skeleton.
> 

Probably the defunctionalization encoding used in the paper on Lightweight 
Higher-Kinded Polymorphism in OCaml 
(https://ocamllabs.github.io/higher/lightweight-higher-kinded-polymorphism.pdf) can help in some way. The corresponding library and examples 
are available at https://github.com/ocamllabs/higher.

The implementation used in the library doesn't perfectly fit the case, because 
the suggested encoding puts the type `t' capturing the type skeleton on an 
unknown depth inside the list of type constructor applications.  I tried the 
following slight variation on the initial encoding:

type ('p, 'f) app = App of 'p * 'f
type nil
type ('a, 'b) typ = .. (* To be used as `('a, M.t) typ' for different `M.t's 
*)

(* Slight change made to pull `M.t' (see below) from the inside of the 
parameter list *)

(* A couple of helper functors similar to the ones in the library *)

module Newtype1 (T : sig type 'a t end) =
struct
  type 'a s = 'a T.t
  type t
  type (_, _) typ += Mk : 'a T.t -> (('a, nil) app, t) typ
  let inj v = Mk v
  let prj (Mk v) = v
end

module Newtype2 (T : sig type ('a, 'b) t end) =
struct
  type ('a, 'b) s = ('a, 'b) T.t
  type t
  type (_, _) typ += Mk : ('a, 'b) T.t -> (('a, ('b, nil) app) app, t) typ
  let inj v = Mk v
  let prj (Mk v) = v
end

(* The common signature for all the skeletons regardless of the number of type 
parameters *)
module type S =
sig
  type t
  type ('a, 'b) mapper = ('a, t) typ -> ('b, t) typ
  
  type task = (* This is just an example of how the mappers can be used *)
      Task :
        ('a, t) typ *
        ('a, 'b) mapper * ('b, 'c) mapper * ('c, 'a) mapper *
        (('a, t) typ -> string) -> task
end

(* The skeleton is captured by M.t .*)
(* The passed type is "('a, M.t) typ" *)
module Performer (M : S) =
struct
  let perform =
    function
    | M.Task  (v, m1, m2, m3, s) ->
      let s = v |> m1 |> m2 |> m3 |> s in
      prerr_endline s
end

(* Example skeleton definitions *)

module Pair =
struct
  include Newtype2 (struct type ('a, 'b) t = 'a * 'b end)
  type ('a, 'b) mapper = ('a, t) typ -> ('b, t) typ
  type task =
      Task : ('a, t) typ * ('a, 'b) mapper * ('b, 'c) mapper * ('c, 'a) mapper 
* (('a, t) typ -> string) -> task
end

module Singleton =
struct
  include Newtype1 (struct type 'a t = 'a end)
  type ('a, 'b) mapper = ('a, t) typ -> ('b, t) typ
  type task =
      Task : ('a, t) typ * ('a, 'b) mapper * ('b, 'c) mapper * ('c, 'a) mapper 
* (('a, t) typ -> string) -> task
end

(* Example usages *)

let mappers =
  (fun (x, y) -> int_of_string x, int_of_string y),
  (fun (x, y) -> float_of_int x, float_of_int y),
  (fun (x, y) -> string_of_float x, string_of_float y)

let pair_tasks =
  let open Pair in
  let m1, m2, m3 = mappers in
  let wrap m x = x |> prj |> m |> inj in
  let m1, m2, m3 = wrap m1, wrap m2, wrap m3 in
  [|Task (inj ("1", "2"), m1, m2, m3, fun x -> let a, b = prj x in a ^ ", " ^ 
b);
    Task (inj (1, 2), m2, m3, m1, fun x -> let a, b = prj x in string_of_int a 
^ ", " ^ string_of_int b)|]

let mappers = int_of_string, float_of_int, string_of_float

let singleton_tasks =
  let open Singleton in
  let m1, m2, m3 = mappers in
  let wrap m x = x |> prj |> m |> inj in
  let m1, m2, m3 = wrap m1, wrap m2, wrap m3 in
  [|Task (inj (1), m2, m3, m1, fun x -> "Just " ^ string_of_int @@ prj x);
    Task (inj ("1"), m1, m2, m3, fun x -> "Just " ^ prj x)|]

module Pair_performer = Performer (Pair)
module Single_performer = Performer (Singleton)

let () = Pair_performer.perform pair_tasks.(0)
(* "1", "2" --> 1, 2 --> 1., 2. --> "1.", "2." --> "1., 2."*)
(* Stderr: 1., 2. *)
let () = Single_performer.perform singleton_tasks.(1)
(* "1" --> 1 --> 1. --> "1." --> "Just 1." *)
(* Stderr: Just 1.*)

let () = Pair_performer.perform pair_task.(1)
(* 1, 2 -> 1., 2. --> "1.", "2." --> Failure: int_of_string *)

-- 
Mikhail Mandrykin
Linux Verification Center, ISPRAS
web: http://linuxtesting.org
e-mail: mandrykin@ispras.ru

  reply	other threads:[~2015-09-09 19:28 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-09-04 20:28 Markus Mottl
2015-09-04 22:19 ` Jacques Garrigue
2015-09-04 23:58   ` Markus Mottl
2015-09-07 18:33     ` Mikhail Mandrykin
2015-09-09 14:00       ` Markus Mottl
2015-09-09 19:28         ` Mikhail Mandrykin [this message]
2015-09-11 15:56           ` Markus Mottl
2015-09-11 16:24             ` Mikhail Mandrykin

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=1527892.mlrKSESLQ8@molnar \
    --to=mandrykin@ispras.ru \
    --cc=caml-list@inria.fr \
    --cc=caml-list@yquem.inria.fr \
    --cc=markus.mottl@gmail.com \
    /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).