From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Original-To: caml-list@sympa.inria.fr Delivered-To: caml-list@sympa.inria.fr Received: from mail2-relais-roc.national.inria.fr (mail2-relais-roc.national.inria.fr [192.134.164.83]) by sympa.inria.fr (Postfix) with ESMTPS id 656A17F747 for ; Thu, 7 Aug 2014 00:06:32 +0200 (CEST) Received-SPF: None (mail2-smtp-roc.national.inria.fr: no sender authenticity information available from domain of trigger0219@gmail.com) identity=pra; client-ip=209.85.220.182; receiver=mail2-smtp-roc.national.inria.fr; envelope-from="trigger0219@gmail.com"; x-sender="trigger0219@gmail.com"; x-conformance=sidf_compatible Received-SPF: Pass (mail2-smtp-roc.national.inria.fr: domain of trigger0219@gmail.com designates 209.85.220.182 as permitted sender) identity=mailfrom; client-ip=209.85.220.182; receiver=mail2-smtp-roc.national.inria.fr; envelope-from="trigger0219@gmail.com"; x-sender="trigger0219@gmail.com"; x-conformance=sidf_compatible; x-record-type="v=spf1" Received-SPF: None (mail2-smtp-roc.national.inria.fr: no sender authenticity information available from domain of postmaster@mail-vc0-f182.google.com) identity=helo; client-ip=209.85.220.182; receiver=mail2-smtp-roc.national.inria.fr; envelope-from="trigger0219@gmail.com"; x-sender="postmaster@mail-vc0-f182.google.com"; x-conformance=sidf_compatible X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AicCACOm4lPRVdy2lGdsb2JhbABagkeBGE0KBIJzrlCDeJVZgV+IUwgWEAEBAQEHCwsJEiuEBAEBAwESEQQZARsdAQMBCwEFBQs3AgIhAQERAQUBHAYTGweICwEDCQihHWqLKYFygxCKVQoZJw1mhTMRAQUOjRGFLYFSBZIHgyWEYIIHgVSMZ4Q5GCmBa4M5IS8 X-IPAS-Result: AicCACOm4lPRVdy2lGdsb2JhbABagkeBGE0KBIJzrlCDeJVZgV+IUwgWEAEBAQEHCwsJEiuEBAEBAwESEQQZARsdAQMBCwEFBQs3AgIhAQERAQUBHAYTGweICwEDCQihHWqLKYFygxCKVQoZJw1mhTMRAQUOjRGFLYFSBZIHgyWEYIIHgVSMZ4Q5GCmBa4M5IS8 X-IronPort-AV: E=Sophos;i="5.01,814,1400018400"; d="scan'208";a="88526405" Received: from mail-vc0-f182.google.com ([209.85.220.182]) by mail2-smtp-roc.national.inria.fr with ESMTP/TLS/RC4-SHA; 07 Aug 2014 00:06:31 +0200 Received: by mail-vc0-f182.google.com with SMTP id hy4so5140247vcb.27 for ; Wed, 06 Aug 2014 15:06:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:sender:in-reply-to:references:date:message-id:subject :from:to:cc:content-type; bh=Lv7H6hdnIU6j33wzDEojhHGgYS6glLsILqh55Sjp5Hc=; b=Li4G0HKrMmXVA3Vhtkfadyh0cUTJBs+AGEt+IZP/2wLYf8bLhmr+duxAhWy0AKiOZ6 tBbS8zkkPjn2Gdz5e2gS7CS5DoFQwzPLCJ5bK8sg5j6PNyHUDI79aW9qDyIsBJtq/MiM qKkmlEJHkvLwOIQHmKmOOQrg7oVI0DJpC/u/R7xnpC6rw+Gaq4wFM9ABLzdzNQijwUKu CyxTBIE1idKDeBw+za8J+bb60c/jzYfGn5PqktL4hGqgCEjqgEmlwIjPvjfJ/o6votjf VwiJ2QCc9HkfzjBMPFBiy6oLST44TKK+qlKCQPLyAO4ZwJ/sps377ifudZaEYs/ILWXS /fCQ== MIME-Version: 1.0 X-Received: by 10.220.118.136 with SMTP id v8mr4234555vcq.50.1407362790601; Wed, 06 Aug 2014 15:06:30 -0700 (PDT) Sender: trigger0219@gmail.com Received: by 10.220.15.3 with HTTP; Wed, 6 Aug 2014 15:06:30 -0700 (PDT) Received: by 10.220.15.3 with HTTP; Wed, 6 Aug 2014 15:06:30 -0700 (PDT) In-Reply-To: References: Date: Wed, 6 Aug 2014 18:06:30 -0400 X-Google-Sender-Auth: xH9fqX4r3tO_eYC0nMuHh13wu5E Message-ID: From: Nick Lucaroni To: Trevor Smith Cc: caml-list@inria.fr Content-Type: multipart/alternative; boundary=001a1133d66c34391f04fffd2fee Subject: Re: [Caml-list] Type Constraints and .mli --001a1133d66c34391f04fffd2fee Content-Type: text/plain; charset=UTF-8 I had come to the same conclusion. On Aug 6, 2014 8:14 AM, "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) > let set_name c name = > 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 > 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. > > The solution I've come to use, that is still pretty readable, is to define > the signature in the .ml file (so no .mli file) and then defining an > internal module which I include (so that I can still reference file name as > the module). So: > > character.ml > > module type CharacterSig = sig > type t > val create : string -> t > val name : t -> string > end > > module T = (CharacterImpl : CharacterSig with type t = CharacterImpl.t) > include T > > However, it seems like there could be a slightly more readable way of > doing this. > > Thoughts? Thank you. > > Trevor > --001a1133d66c34391f04fffd2fee Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable

I had come to the same conclusion.

On Aug 6, 2014 8:14 AM, "Trevor Smith"= <trevorsummerssmith@gma= il.com> 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 constraint= s to a signature defined in a .mli in that same .mli file?"

Detailed problem:=C2=A0You want to have a read interface and a wr= ite interface for the same implementation.

<= div style=3D"font-family:arial,sans-serif;font-size:13px">We'll use a t= rivial example with a character and a name.

module type CharacterSig =3D sig
=C2=A0 val t
=C2=A0 val create : string -> t
=C2=A0 val name : t -> string
end

module type MutableCharacterSig =3D s= ig
<= div>=C2=A0 val t
=C2=A0 val create : string -> t
=C2=A0 val name : t -> string=
=C2=A0 val set_name : t -> stri= ng -> unit
end

module CharacterImpl =3D struct<= /font>
=C2=A0 type t =3D {n= ame : string ref}
= =C2=A0 let create name =C2=A0=3D
=C2=A0 =C2=A0 {name =3D ref name= }
=C2=A0 let name c= =3D !(c.name)
=C2=A0 let set_name c name =3D<= /font>
=C2=A0 =C2=A0=C2=A0c.name=C2=A0:=3D name
= end

module Character =3D (CharacterImpl : Chara= cterSig with type t =3D CharacterImpl.t)
module MutableC= haracter =3D (CharacterImpl : MutableCharacterSig with type t =3D Character= Impl.t)

But wh= at I would like is to specify the read and write signatures in .mli files f= or a more readable codebase.

So:

character.mli:
=C2=A0 val t
=C2=A0 val create : string -> t
=C2=A0 val name : t ->= ; string

mCharacter.mli:
=C2=A0 val t
= =C2=A0 val create : string -> t
=C2=A0 val name : t -> string
=C2=A0 val set_nam= e : t -> string -> unit

charac= terImpl.ml (* ... implementation as above ... *)

However, it is not clear to me that there is a way to attach the type const= raint to character.mli and mCharacter.mli, while keeping the terse readabil= ity of the .mli file. One idea for a solution, would be to reference a &quo= t;this" so that the interface could show that it was being implemented= by CharacterImpl, and include the type constraint.

The solution I've = come to use, that is still pretty readable, is to define the signature in t= he .ml file (so no .mli file) and then defining an internal module which I = include (so that I can still reference file name as the module). So:


module type CharacterS= ig =3D sig
=C2=A0 = =C2=A0 type t
=C2=A0= =C2=A0 val create : string -> t
=C2=A0 =C2=A0 val name : t ->= string
end

module T =3D (CharacterImpl : CharacterSig = with type t =3D CharacterImpl.t)
include T

However, it seems like the= re could be a slightly more readable way of doing this.

Thoughts? Thank you.

Trevor
--001a1133d66c34391f04fffd2fee--