caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* Dichotomy between functions and type constructors?
@ 2000-02-18 20:47 David McClain
  2000-02-21 19:31 ` Markus Mottl
  2000-02-25 14:28 ` Xavier Leroy
  0 siblings, 2 replies; 4+ messages in thread
From: David McClain @ 2000-02-18 20:47 UTC (permalink / raw)
  To: caml-list

I am curious about the apparent dichotomy between normal functions and type
constructors, and why this disparity exists?

Say I have a type

type thing =
   T1 of int * float
| ....

I can create such a type as T1(5, 3.14) but I cannot create such a type on a
tuple result of a function call:

let doit x = (x, float_of_int x)

let myT1 = T1(doit x)

This gives rise to a type checking error wherein the constructor T1 demands
two arguments, instead of demanding a tuple of two elements.

SML does not appear to impose this same requirement on the programmer, so
what is the origin of the OCaml requirement?

TIA,

David McClain, Sr. Scientist
Raytheon Systems Co.
Tucson, AZ




^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Dichotomy between functions and type constructors?
  2000-02-18 20:47 Dichotomy between functions and type constructors? David McClain
@ 2000-02-21 19:31 ` Markus Mottl
  2000-02-25 14:28 ` Xavier Leroy
  1 sibling, 0 replies; 4+ messages in thread
From: Markus Mottl @ 2000-02-21 19:31 UTC (permalink / raw)
  To: David McClain; +Cc: OCAML

> Say I have a type
> 
>    T1 of int * float

> I can create such a type as T1(5, 3.14) but I cannot create such a type on a
> tuple result of a function call:
> 
> let doit x = (x, float_of_int x)
> 
> let myT1 = T1(doit x)

This is a trap into which I have already fallen when I tried to find a bug
in a C-interface. Xavier explained the "problem" to me when I sent a bug
report, because I had thought that the source of the error originated in
OCaml:

  type t = T1 of int * float

is *not* the same as:

  type t = T1 of (int * float)

The first one is an example of a dataconstructor that takes two arguments
(an int and a float), whereas the second one is a dataconstructor that
takes *one* argument which happens to be a tuple...

So this, for example, works:

  type t = T1 of (int * float)

  let doit x = (x, float_of_int x)
  let myT1 x = T1(doit x)

I haven't taken a look at the FAQs, whether this misunderstanding is
already explained there. In any case, it should be mentioned somewhere,
because it is a somewhat surprising fact (if you haven't seen it before).
It is especially difficult to find the bug if you create data in C the
wrong way and wonder why the program keeps crashing: in contrast to the
multi-argument case the tuple case is represented internally with an
indirection...

Best regards,
Markus Mottl

-- 
Markus Mottl, mottl@miss.wu-wien.ac.at, http://miss.wu-wien.ac.at/~mottl




^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Dichotomy between functions and type constructors?
  2000-02-18 20:47 Dichotomy between functions and type constructors? David McClain
  2000-02-21 19:31 ` Markus Mottl
@ 2000-02-25 14:28 ` Xavier Leroy
  1 sibling, 0 replies; 4+ messages in thread
From: Xavier Leroy @ 2000-02-25 14:28 UTC (permalink / raw)
  To: David McClain, caml-list

> Say I have a type
> 
> type thing =
>    T1 of int * float
> | ....
> 
> I can create such a type as T1(5, 3.14) but I cannot create such a type on a
> tuple result of a function call:
> 
> let doit x = (x, float_of_int x)
> let myT1 = T1(doit x)
> 
> This gives rise to a type checking error wherein the constructor T1 demands
> two arguments, instead of demanding a tuple of two elements.
> 
> SML does not appear to impose this same requirement on the programmer, so
> what is the origin of the OCaml requirement?

For reasonable performance, a datatype definition such as "thing" above
must not represent values of type "thing" literally, i.e. as a block tagged 
"T1" pointing to a two-field block representing a pair (integer, float). 
It is crucial performance-wise to fold the two blocks into one block 
tagged "T1" holding the integer and the float. Pretty much all ML compilers 
do this. 

Without modules, the compiler can still maintain the illusion that 
T1 is really a one-argument constructor containing a pair, and not a 
two-argument constructor. Accesses such as 

        match x with T1 p -> p 

are not terribly efficient (the pair is actually reconstructed on the 
right-hand side in Caml Light), but they work. 

The big problem is with modules and data abstraction. Namely, should 
we allow the following structure 

        struct type p = int * float 
               type thing = T1 of int * float 
               ... 
        end 

to match the following signature 

        sig type p 
              type thing = T1 of p 
        end 

If you believe the SML/Camllight illusion that constructors have 0 or 
1 argument, then the answer should be "yes". However, this causes no 
end of trouble in a compiler, because code typechecked against the 
signature above assumes that values of type thing are one-field blocks 
pointing to a value of type p, while code internal to the structure 
assumes two-field blocks from which values of type p must be 
reconstructed. 

This problem has plagued the SML/NJ implementation for quite a while, 
and the solutions that have been proposed are all extremely 
heavy-weight. 

I think it's not worth the effort to maintain the illusion that 
constructors have 0 or 1 argument. Let's just face the truth and 
consider them as N-ary, as in Prolog. 

Incidentally, if you *really* need a constructor with one argument 
that is a pair, you can always declare it as 

        type p = int * float 
        type thing = T1 of p 

This will direct the OCaml compiler to use the proper representation for a 
one-argument constructor. Of course, that representation will occupy 
twice as much space as that of "type thing = T1 of int * float", and be 
twice as slow to access. 

- Xavier Leroy



^ permalink raw reply	[flat|nested] 4+ messages in thread

* RE: Dichotomy between functions and type constructors?
@ 2000-02-21 18:02 Don Syme
  0 siblings, 0 replies; 4+ messages in thread
From: Don Syme @ 2000-02-21 18:02 UTC (permalink / raw)
  To: 'David McClain', caml-redistribution

I believe it's got something to do with cross module optimization.  However,
I've always wondered why the restriction is not lifted at least inside the
module where the constructor is declared.

Cheers,
Don


-----Original Message-----
From: David McClain [mailto:dmcclain@azstarnet.com]
Sent: 21 February 2000 17:09
To: caml-redistribution@pauillac.inria.fr
Subject: Dichotomy between functions and type constructors?


I am curious about the apparent dichotomy between normal functions and type
constructors, and why this disparity exists?

Say I have a type

type thing =
   T1 of int * float
| ....

I can create such a type as T1(5, 3.14) but I cannot create such a type on a
tuple result of a function call:

let doit x = (x, float_of_int x)

let myT1 = T1(doit x)

This gives rise to a type checking error wherein the constructor T1 demands
two arguments, instead of demanding a tuple of two elements.

SML does not appear to impose this same requirement on the programmer, so
what is the origin of the OCaml requirement?

TIA,

David McClain, Sr. Scientist
Raytheon Systems Co.
Tucson, AZ



^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2000-02-25 17:04 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2000-02-18 20:47 Dichotomy between functions and type constructors? David McClain
2000-02-21 19:31 ` Markus Mottl
2000-02-25 14:28 ` Xavier Leroy
2000-02-21 18:02 Don Syme

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).