From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail4-relais-sop.national.inria.fr (mail4-relais-sop.national.inria.fr [192.134.164.105]) by walapai.inria.fr (8.13.6/8.13.6) with ESMTP id p9GKsllw018683 for ; Sun, 16 Oct 2011 22:54:47 +0200 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AtcBAAFEm05KfVK2kGdsb2JhbABCFoRflFuPCggiAQEBAQkJDQcUBCGBbgEBAQMBEgIPBBkBGxACCwEDAQsGAwILDQICCR0CAiIBEQEFAQoSBhMSEIddCJgyCosMRYJgg309iG4CBQqBJoF7g0mBFASTeo0qPYNx X-IronPort-AV: E=Sophos;i="4.69,354,1315173600"; d="scan'208";a="113105900" Received: from mail-wy0-f182.google.com ([74.125.82.182]) by mail4-smtp-sop.national.inria.fr with ESMTP/TLS/RC4-SHA; 16 Oct 2011 22:54:42 +0200 Received: by wyi40 with SMTP id 40so1972152wyi.27 for ; Sun, 16 Oct 2011 13:54:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc:content-type:content-transfer-encoding; bh=TyT3ryr103+xJDK3MbRh1cYUq6seRsSEc61tsWMDsNQ=; b=D4CTiX/4+DVPSAf/TuI+8ZgXOnev20ZW/cn1TVtb0JmdK+o8o9p80F6zdlHnlPKGWT drSE2XLcXJLIJC5qgHhuA2cX2FY2UNiYSqRVsjw0mRajDQbhURtxVc4noe8DWbFPs20G 5twYes05+wBLiDjLeUbbXrU1YO6mI6pP/ZO3M= Received: by 10.227.195.13 with SMTP id ea13mr5673973wbb.36.1318798481136; Sun, 16 Oct 2011 13:54:41 -0700 (PDT) MIME-Version: 1.0 Received: by 10.227.155.67 with HTTP; Sun, 16 Oct 2011 13:54:21 -0700 (PDT) In-Reply-To: <4E9B3D66.6080203@fiit.stuba.sk> References: <4E9B27A1.5070309@fiit.stuba.sk> <4E9B3D66.6080203@fiit.stuba.sk> From: Gabriel Scherer Date: Sun, 16 Oct 2011 22:54:21 +0200 Message-ID: To: =?UTF-8?B?TWF0ZWogS2/FocOtaw==?= Cc: caml-list@inria.fr Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-MIME-Autoconverted: from quoted-printable to 8bit by walapai.inria.fr id p9GKsllw018683 Subject: Re: [Caml-list] Ocaml: typing by name vs. typing by structure > Similarly, you cannot do this > type t = A of {l1:int} > | B of {l2:float} > | C of {l1:int; l2:float} You can do that with object types: type t = | A of < l1 : int > | B of < l2 : float > | C of < l1 : int; l2 : float > Similarly, polymorphic variants are structural counterparts of variant types. # if true then `Foo (object method l1 = 1 end) else `Bar (object method l1 = 2 method l2 = 2. end);; - : [> `Bar of < l1 : int; l2 : float > | `Foo of < l1 : int > ] = `Foo Those types are more complex to use that named variant and structures, tend to generate hard-to-read error messages (unless you carefully annotate your code to avoid having too many unknowns in the exact type used), and are slightly less efficient at runtime. Flexibility comes at a price. Most Ocaml programmers actually favor plain, simple language constructs. Objects and polymorphic variants are used when their flexibility is clearly required by the application, which is actually not very often. You can learn more about objects in the OCaml manual, and about polymorphic variant in Jacques Garrigue's article "Code reuse through polymorphic variants": - http://caml.inria.fr/pub/docs/manual-ocaml/manual005.html - http://www.math.nagoya-u.ac.jp/~garrigue/papers/fose2000.html On Sun, Oct 16, 2011 at 10:24 PM, Matej Košík wrote: > On 10/16/2011 09:24 PM, Gabriel Scherer wrote: >> If record were structurally typed, there would be an ambiguity as to, >> for example, what this function mean: >> >>   let access_foo t = t.foo >> >> What would the type of `access_foo` be ? { foo : 'a } -> 'a ? { foo : >> 'a; bar : 'b } -> 'a ? > > { foo : 'a } -> 'a > > seems plasible > >> Should `access_foo { foo = 1 }` be typable? And `access_foo { foo = 1; >> bar = true }` ? >> >> In this situation, you want record subtyping. This get more >> complicated than the relatively simple OCaml records. > > This may be too troublesome to support but I guess it is plausible language change and it would enable additional Ocaml terseness. Let me clarify. > > At the moment, it is not possible to do this: > >  type t = {l1:int} * {l2:int};; > > It is a syntax error. We are forced to do it gradually: > >  type t1 = { l1 : int; } >  type t2 = { l2 : int; } >  type t = t1 * t > > This is somewhat cumbersome. > > Similarly, you cannot do this > >  type t = A of {l1:int} >         | B of {l2:float} >         | C of {l1:int; l2:float} > > Only this works: > >  type t1 = { l1 : int} >  type t2 = { l2 : float} >  type t3 = { l1 : int; l2: float} >  type t = A of t1 >         | B of t2 >         | C of t3 > > We were forced to introduce three superfluous type-names [t1;t2;t3]. > How would you feel if you were forced to do that for every tuple-type? > > Sometimes tuples are not ideal > (when they have lots of members) > Records are better in those cases because you can access elements by their label and when you construct records with lots of fields, the labels clarify which field has what meaning. But switching from tuples to records is not smooth. What could be gained in readability (labeled fields) is lost by cluttering the program by auxiliary record type definitions. > >> In fact, OCaml >> has structurally typed structures with named fields : objects >> >>   # let access_foo t = t#foo;; >>   val access_foo : < foo : 'a; .. > -> 'a = >>   # access_foo (object method foo = 1 method bar = true end);; >>   - : int = 1 > > Interesting. > >> >> Tuples don't have this issue as they don't have an universal accessor >> function : there is no way to get the first element of a tuple >> whatever its width is. Therefore, all tuples manipulation make the >> structure concrete, and structural subtyping comes at no complexity >> cost ... if you accept the absence of universal accessors. SML has >> them (#1 #2 etc.) and I'm not sure how they handle this. > > -- > Matej Košík > > -- > 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 > >