From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.1.3 (2006-06-01) on yquem.inria.fr X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=AWL autolearn=disabled version=3.1.3 X-Original-To: caml-list@yquem.inria.fr Delivered-To: caml-list@yquem.inria.fr Received: from mail1-relais-roc.national.inria.fr (mail1-relais-roc.national.inria.fr [192.134.164.82]) by yquem.inria.fr (Postfix) with ESMTP id 9BA32BBC4 for ; Thu, 16 Apr 2009 18:05:54 +0200 (CEST) X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AmgIANDz5knZSMDjZmdsb2JhbACBU5RTDQsDBQkPBbpcg30G X-IronPort-AV: E=Sophos;i="4.38,431,1233529200"; d="scan'208";a="27803331" Received: from fmmailgate02.web.de ([217.72.192.227]) by mail1-smtp-roc.national.inria.fr with ESMTP; 16 Apr 2009 18:05:54 +0200 Received: from smtp08.web.de (fmsmtp08.dlan.cinetic.de [172.20.5.216]) by fmmailgate02.web.de (Postfix) with ESMTP id D51F2FD1E9B2; Thu, 16 Apr 2009 18:05:53 +0200 (CEST) Received: from [78.43.226.218] (helo=frosties.localdomain) by smtp08.web.de with smtp (WEB.DE 4.110 #277) id 1LuU65-0002u7-00; Thu, 16 Apr 2009 18:05:53 +0200 Received: from mrvn by frosties.localdomain with local (Exim 4.69) (envelope-from ) id 1LuU65-0007tj-Bp; Thu, 16 Apr 2009 18:05:53 +0200 From: Goswin von Brederlow To: Pal-Kristian Engstad Cc: "yminsky@gmail.com" , "caml-list@inria.fr" Subject: Re: [Caml-list] pattern matching and records vs tuples References: <87skkbuxx8.fsf@aryx.cs.uiuc.edu> <891bd3390904141744k4516f3d0y551f6c572ccadad5@mail.gmail.com> <49E53C8A.1090601@naughtydog.com> Date: Thu, 16 Apr 2009 18:05:53 +0200 In-Reply-To: <49E53C8A.1090601@naughtydog.com> (Pal-Kristian Engstad's message of "Tue, 14 Apr 2009 18:46:50 -0700") Message-ID: <87tz4opori.fsf@frosties.localdomain> User-Agent: Gnus/5.110006 (No Gnus v0.6) XEmacs/21.4.21 (linux) MIME-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: 8bit Sender: goswin-v-b@web.de X-Sender: goswin-v-b@web.de X-Provags-ID: V01U2FsdGVkX18v6wEiwLcTEXJWamMVjsnKiboR5rBoM0/UgaGL gcTbUl92Fct/EgISNU9NtN3RjddtwwgCVDlmdIxHpC77/fgxGB Yi/zO1OZw= X-Spam: no; 0.00; foo:01 foo:01 pke:01 yaron:01 minsky:01 val:01 subtype:01 val:01 subtypes:01 subtype:01 inference:01 baz:01 baz:01 occuring:01 syntax:01 Pal-Kristian Engstad writes: > Honestly, I'd prefer to have to annotate non-exhaustive records: >     let { foo = foo; bar = bar } = x > should only match { foo; bar }, but >     let { foo = foo; bar =  bar; .. } = x, > can match records with more labels. > PKE. > Yaron Minsky wrote: I would actually like to propose that to work on a type level. Currently we have: ---------------------------------------------------------------------- # type base = { x : int } let get_x r = r.x type more = { x : int; y : int };; type base = { x : int; } val get_x : base -> int = type more = { x : int; y : int; } # get_x { x=1; y=2; };; Error: This expression has type more but is here used with type base ---------------------------------------------------------------------- I propose that records can be subtyped if their prefix matches and ".." would be used to denote the subtype of any record with this prefix: # type base = { x : int } let get_x r = r.x type more = { x : int; y : int };; type base = { x : int; } val get_x : base -> int = type more = { x : int; y : int; } # get_x ({ x=1; y=2; } :> base);; - : int = 1 One could also declare get_x to accept supertypes: # let get_x (r : { x : int; .. }) = r.x; val get_x : { x : int; .. } -> int = # get_x { x=1; y=2; };; - : int = 1 I think there is only one thing that would need to be changed for the compiled code with record subtypes like the above. Copying and modifying a record would need allocate a block matching the size of the input record and not the size of the subtype. Think about this code: # let change_x (r : { x : int; .. }) x = { r with x = x } val change_x : { x : int; .. } as 'a -> int -> 'a = # change_x { x=1; y=2; } 2;; - : more = {x = 2; y = 2} All other changes would only affect the grammar and type inference I think. Now what would happen with your example? # type record = { foo : int; bar : float; baz : string } type record = { foo : int; bar : float; baz : string; } # let f x = let { foo = foo; bar = bar; .. } = x in (foo, bar) What type is that? 1) val f : { foo : int; bar : float; baz : string; .. } -> int * float = 2) val f : record -> int * float = 3) val f : { foo : int; bar : float; .. } -> int * float = 4) val f : { foo : 'a; bar : 'b; .. } -> 'a * 'b = I would say it should result in 3. And the type should always be the minimum prefix required to match all occuring fields: # let f x = let { foo = foo; baz = baz; .. } = x in (foo, baz) val f : { foo : int; bar : float; baz : string; .. } -> int * string = As a further extention the following syntax would be usefull: # type base = { x : int } type more = { base with y : int };; type base = { x : int; } type more = { x : int; y : int; } With this syntax more would always be a supertype of base even if the base type gets altered. MfG Goswin