caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Jeremy Yallop <yallop@gmail.com>
To: Christophe Raffalli <christophe@raffalli.eu>
Cc: "caml-list@inria.fr" <caml-list@inria.fr>
Subject: Re: [Caml-list] module equality
Date: Tue, 20 Jun 2017 11:05:44 +0100	[thread overview]
Message-ID: <CAAxsn=EzRqDoz_sm5OVC0FChL2tBFQP1W44N3z_YDm8ctE6ecQ@mail.gmail.com> (raw)
In-Reply-To: <20170620093641.ovz6dnsghtdj6tv6@delli7.univ-savoie.fr>

Dear Christophe,

On 20 June 2017 at 10:36, Christophe Raffalli <christophe@raffalli.eu> wrote:
> I thought that two applications of Set.Make to
> the same module would result in two distinct
> modules with two distinct types 't'.
>
> This is not the case

Right: in OCaml, two applications of a functor to the same module path
have signatures with equal type components.  This type of functor is
called "applicative", as opposed to the "generative" functors found in
Standard ML.  Generative functors have the behaviour you were
expecting, with each application generating fresh type components.
However, applicative functors allow many programs to be given types
that are rejected when functors are generative.  (There are a few
examples nowadays of programs that can be given types with generative,
but not applicative, functors, but they're fairly obscure.)

In your example:

> module F(O:Set.OrderedType) : S with type elt = O.t = struct
[...]
> module M1 = F(Int)
> module M2 = F(Int)

the two applications of F both have the signature

     sig ... type t = F(Int).t ... end

i.e. both M1.t and M2.t are equal to the type F(Int).t, and so values
of those types can be mixed freely.  However, although the types
resulting from the functor applications are shared, the values
resulting from the application (i.e. M1 and M2) are not equivalent.
People occasionally find this combination -- sharing of types without
sharing of values -- surprising, since types are often used to
determine whether values are compatible in terms of both
representation and behaviour.

There are a couple of ways to ensure that applications of F to the
same module build modules with incompatible types.  First, the
applicative behaviour only holds for paths, so you can force
incompatibility at the call site by passing a module expression that
is not a path as an argument:

   module M1 = F(struct include Int end)
   module M2 = F(struct include Int end)

  # fun (x : M1.t) -> (x : M2.t);;
  Characters 19-20:
    fun (x : M1.t) -> (x : M2.t);;
                       ^
  Error: This expression has type M1.t but an expression was expected of type
           M2.t

Alternatively, you can mark the functor as generative at the
definition site by adding an additional parameter '()':

   module F(O:Set.OrderedType) () : S with type elt = O.t = struct
   ...

which requires each caller of F to provide a corresponding argument

   module M1 = F(Int) ()
   module M2 = F(Int) ()

and once again generates modules whose signatures have distinct type components.

Since the surprising behaviour only arises when functor applications
have effects, Andreas Rossberg has advocated connecting the
applicative/generative distinction with the purity/effectful
distinction, making pure functors applicative and effectful functors
generative.  OCaml doesn't enforce this behaviour, but it's a
reasonably pattern to follow when writing programs.

Kind regards,

Jeremy

      parent reply	other threads:[~2017-06-20 10:05 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-06-20  9:36 Christophe Raffalli
2017-06-20 10:03 ` Dario Teixeira
2017-06-20 10:05 ` Jeremy Yallop [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='CAAxsn=EzRqDoz_sm5OVC0FChL2tBFQP1W44N3z_YDm8ctE6ecQ@mail.gmail.com' \
    --to=yallop@gmail.com \
    --cc=caml-list@inria.fr \
    --cc=christophe@raffalli.eu \
    /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).