caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Gabriel Scherer <gabriel.scherer@gmail.com>
To: Walter Cazzola <cazzola@dico.unimi.it>
Cc: OCaML Mailing List <caml-list@inria.fr>
Subject: Re: [Caml-list] with clause
Date: Sun, 9 Oct 2011 17:42:44 +0200	[thread overview]
Message-ID: <CAPFanBHZ9+bxTdtdqP=m_dMt9U9yq6bZpUYt+-pxniWvdJteAg@mail.gmail.com> (raw)
In-Reply-To: <alpine.LFD.2.00.1110071828480.3251@surtur.dico.unimi.it>

The "with type foo = ..." construct is meant to be used on signatures
(module interfaces), not on structures (module implementations).

First, a remark: if you want to share code, it's not terribly
comfortable if it's split into three different files of five lines
each. You could put your three modules in the same file, and that
would be easier to distribute:

  module type OpVarADT =
   sig
     type a and b and c
     val op: a -> b -> c
     val init : c
   end

  module VarArgs (OP : OpVarADT) =
    struct
      let arg x = fun y rest -> rest (OP.op x y) ;;
      let stop x = x;;
      let f g = g OP.init;;
    end

  module ListConcat = struct
    type a and b = a list and c = a list
    let op = fun (x: a) y -> y @ [x] ;;
    let init = [] ;;
  end

The problem in your code is that, in ListConcat, "type a" is an
abstract type (because it is not of the form "type a =  ...") in an
implementation.
An abstract type in a signature means "there is some concrete
definition that I hide for encapsulation".
An abstract type in an implementation has no definition at all; for
all purposes, it's an unique empty type. You don't have any value of
type `a` and, therefore, you can't use your ListConcat module. You
*can* apply the VarArgs functor to it but the result is useless:

  module M = VarArgs(ListConcat);;

M.arg takes an argument of type ListConcat.a and nobody knows how to
build such a value.

So you were wrong to use an abstract type where in reality you wanted
an parametric type. What you mean is probably something like

  module ListConcat = struct
    type 'a b = 'a list
    ...
  end

However, this is not satisfying as it doesn't respect the OpVarADT
signature, which specifies that the type b is not parametrized. So
with that definition you can't apply VarArgs anymore.

  module ListConcatParam = struct
    type a and 'a b = 'a list and c = a list
    let op = fun (x: a) y -> y @ [x] ;;
    let init = [] ;;
  end

 # module M = VarArgs(ListConcatParam);;
 Type declarations do not match:
    type 'a b = 'a list
  is not included in
     type b
  They have different arities.

So how can you have a type that is somehow parametrized (to be able to
use this ListConcat module with different types of list elements) and
still respect the 0-arity signature ? The answer is the following : if
you can't use parametrized type of the base OCaml language, you can
use the module language to add parametrization, by making your
ListConcat module a functor over a type:

  module ListConcatFunctor (T : sig type t end) = struct
    type a = T.t and b = a list and c = a list
    let op = fun (x: a) y -> y @ [x] ;;
    let init = [] ;;
  end

  module M = VarArgs(ListConcatFunctor(struct type t = int end));;

  # M.f (M.arg 2) (M.arg 3) (M.arg 4) M.stop;;
  - : int list = [2; 3; 4]

It's quite normal you had difficulty with this as a beginner;
combining parametric types and the module systems is one of the most
delicate aspects of the language. Most people don't actually use
functors very often.

On Fri, Oct 7, 2011 at 6:37 PM, Walter Cazzola <cazzola@dico.unimi.it> wrote:
> Dear all,
> I'm still stucked on my example to write a functor for functions with a
> variable number of arguments. In particular I can't instantiate it with
> a generic list ('a list).
>
> Attached you find my code. Sometimes ago some on the list suggested me
> to  use with to specify the value of the generic type (a in my case but
> I can't get rid of its syntax, what I think correct is:
>
>  module M1 = VarArgs(ListConcat with type ListConcat.a = int) ;;
>
> but I get a syntax error on the with.
>
> Please note that I'd like to keep OpVarADT and varargs independent of
> the concrete type of a.
>
> Any help to solve this riddle would be appreciated.
>
> TIA
> Walter
>
> --
> --
> Caml-list mailing list.  Subscription management and archives:
> https://sympa-roc.inria.fr/wws/info/caml-list
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
>
>


      reply	other threads:[~2011-10-09 15:43 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-10-07 16:37 Walter Cazzola
2011-10-09 15:42 ` Gabriel Scherer [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='CAPFanBHZ9+bxTdtdqP=m_dMt9U9yq6bZpUYt+-pxniWvdJteAg@mail.gmail.com' \
    --to=gabriel.scherer@gmail.com \
    --cc=caml-list@inria.fr \
    --cc=cazzola@dico.unimi.it \
    /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).