caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: "Török Edwin" <edwin+ml-ocaml@etorok.net>
To: caml-list@inria.fr
Subject: Re: [Caml-list] Type Constraints and .mli
Date: Wed, 06 Aug 2014 18:36:54 +0300	[thread overview]
Message-ID: <53E24B96.8080402@etorok.net> (raw)
In-Reply-To: <CAG-KTt_4CUmxmpoww-5aAR_4o5WH7hq_Dah1ENrHzA1ZHq4ogA@mail.gmail.com>

On 08/06/2014 03:14 PM, Trevor Smith wrote:
> Hello,
> 
> I have a question about using .mli files for increased readability. I think my question boils down to: "Can one tersely add type constraints to a signature defined in a .mli in that same .mli file?"
> 
> Detailed problem: You want to have a read interface and a write interface for the same implementation.
> 
> We'll use a trivial example with a character and a name.
> 
> module type CharacterSig = sig
>   val t
>   val create : string -> t
>   val name : t -> string
> end
> 
> module type MutableCharacterSig = sig
>   val t
>   val create : string -> t
>   val name : t -> string
>   val set_name : t -> string -> unit
> end
> 
> module CharacterImpl = struct
>   type t = {name : string ref}
>   let create name  =
>     {name = ref name }
>   let name c = !(c.name <http://c.name/>)
>   let set_name c name =
>     c.name <http://c.name/> := name
> end
> 
> module Character = (CharacterImpl : CharacterSig with type t = CharacterImpl.t)
> module MutableCharacter = (CharacterImpl : MutableCharacterSig with type t = CharacterImpl.t)
> 
> But what I would like is to specify the read and write signatures in .mli files for a more readable codebase.
> 
> So:
> 
> character.mli:
>   val t

shouldn't this be a type?

>   val create : string -> t
>   val name : t -> string
> 
> mCharacter.mli:
>   val t
>   val create : string -> t
>   val name : t -> string
>   val set_name : t -> string -> unit
> 
> characterImpl.ml (* ... implementation as above ... *)
> 
> However, it is not clear to me that there is a way to attach the type constraint to character.mli and mCharacter.mli, while keeping the terse readability of the .mli file. One idea for a solution, would be to reference a "this" so that the interface could show that it was being implemented by CharacterImpl, and include the type constraint.

Not sure I understood exactly what you want to do, but using 'include module type of' and 'type t = CharacterImpl.t' should work:

character.mli
type t = CharacterImpl.t
val create : string -> t
val name : t -> string

character.ml:
include CharacterImpl

mCharacter.mli:
include module type of Character
val set_name : t -> string -> unit

mCharacter.ml:
include CharacterImpl

characterImpl.ml:
type t = {name : string ref}
let create name  =
  {name = ref name }
let name c = !(c.name)
let set_name c name =
  c.name := name

However in this case Character.t = MCharacter.t = CharacterImpl.t, so you won't get the type safety you want
(A Character.t can still be modified by MCharacter.set_name).

Perhaps it'd be better to use different types, though to_character is not the identity function:

character.mli:
type t
val create : string -> t
val name : t -> string

mCharacter.mli:
include module type of Character
val set_name : t -> string -> unit
val to_character : t -> Character.t

character.ml:
include MCharacter

mCharacter.ml:
type t = {name : string ref}
let create name  =
  {name = ref name }
let name c = !(c.name)
let set_name c name =
  c.name := name

let to_character x = Character.create (name x)

In fact you should probably take a look at String and Bytes type in OCaml 4.02 (and the ocaml-bytes compatibility lib for <4.0.2).

I'd prefer something simpler though:

character.ml:
type u = {name : string ref}
type 'a t = u

let create name  =
  {name = ref name }
let create_ro = create
let create_rw = create
let name c = !(c.name)
let set_name c name =
  c.name := name
let readonly x = x

character.mli:
type 'a t constraint 'a = [< `W | `R]
val create_ro : string -> [`R] t
val create_rw : string -> [`R | `W] t
val name : 'a t -> string
val set_name : [> `W] t -> string -> unit
val readonly : [> `R] t -> [`R] t

Best regards,
--Edwin

  reply	other threads:[~2014-08-06 15:36 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-08-06 12:14 Trevor Smith
2014-08-06 15:36 ` Török Edwin [this message]
2014-08-07 22:06   ` Trevor Smith
2014-08-08  8:19     ` Frédéric Bour
2014-08-06 22:06 ` Nick Lucaroni

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=53E24B96.8080402@etorok.net \
    --to=edwin+ml-ocaml@etorok.net \
    --cc=caml-list@inria.fr \
    /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).