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=1.1 required=5.0 tests=AWL,SPF_NEUTRAL autolearn=disabled version=3.1.3 X-Original-To: caml-list@yquem.inria.fr Delivered-To: caml-list@yquem.inria.fr Received: from discorde.inria.fr (discorde.inria.fr [192.93.2.38]) by yquem.inria.fr (Postfix) with ESMTP id 4ED1BBC69 for ; Fri, 4 May 2007 01:16:45 +0200 (CEST) Received: from nz-out-0506.google.com (nz-out-0506.google.com [64.233.162.236]) by discorde.inria.fr (8.13.6/8.13.6) with ESMTP id l43NGiJp028181 for ; Fri, 4 May 2007 01:16:44 +0200 Received: by nz-out-0506.google.com with SMTP id s1so722459nze for ; Thu, 03 May 2007 16:16:43 -0700 (PDT) DKIM-Signature: a=rsa-sha1; c=relaxed/relaxed; d=gmail.com; s=beta; h=domainkey-signature:received:received:message-id:date:from:to:subject:cc:in-reply-to:mime-version:content-type:content-transfer-encoding:content-disposition:references; b=U3JdEi59z65afICjzzgIwX8ZmdZRti4gcppkjY+VrzgDutsbSkb5P5F3nP6zCdahwLvmIrWkpkwxDM+feiSk9aO8Dsy9NCqqeYxPEI43HTxg8WX8cRiwRIHtFQ+Uo6zHBVKF7bOlB9d89SK2j5PB/hWcRSSdM0DjZqOUQBplMFk= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=beta; h=received:message-id:date:from:to:subject:cc:in-reply-to:mime-version:content-type:content-transfer-encoding:content-disposition:references; b=ZDL22iSkLzm/O9WtXKHSfPzBdjbP/IYgcPxbftikyncYE0+auqyk0Qe4AFe/AFDk6LiGRg4TOas+vJUxxtDnndk+OP507PTddTF6CHFX9dx2jxLgYbJ1bG8K4wv4xyjiO53UcQvzMo98ZeKaUpYJGlmDdZto71tCFBFvHx7iZzc= Received: by 10.114.155.1 with SMTP id c1mr734860wae.1178234202516; Thu, 03 May 2007 16:16:42 -0700 (PDT) Received: by 10.114.235.17 with HTTP; Thu, 3 May 2007 16:16:42 -0700 (PDT) Message-ID: <875c7e070705031616w50ca595m2e55bda049ba7aa6@mail.gmail.com> Date: Thu, 3 May 2007 19:16:42 -0400 From: "Chris King" To: "Christopher L Conway" Subject: Re: [Caml-list] wrapping parameterized types Cc: caml-list@yquem.inria.fr In-Reply-To: <4a051d930705031531m396e42e7i6212137e2fb9cd53@mail.gmail.com> MIME-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-Disposition: inline References: <4a051d930705031531m396e42e7i6212137e2fb9cd53@mail.gmail.com> X-j-chkmail-Score: MSGID : 463A6D5C.000 on discorde : j-chkmail score : X : 0/20 1 0.000 -> 1 X-Miltered: at discorde with ID 463A6D5C.000 by Joe's j-chkmail (http://j-chkmail . ensmp . fr)! X-Spam: no; 0.00; mylist:01 strlist:01 mylist:01 strlist:01 o'caml:01 arbitrarily:01 o'caml:01 popping:01 coerced:01 existential:01 prefixing:01 existential:01 val:01 handing:01 polymorphic:01 On 5/3/07, Christopher L Conway wrote: > # let app_to_mylist f = function Intlist x -> f x | Strlist x -> f x ;; > Characters 65-66: > let app_to_mylist f = function Intlist x -> f x | Strlist x -> f x ;; > ^ > This expression has type string list but is here used with type int list The problem is, when O'Caml tries to infer the type of f, it arbitrarily chooses string list -> 'a and dies when it finds it applied to an int list. And although the type you want is 'a list -> 'b, O'Caml certainly won't infer this, since you'd have polymorphic functions like that popping up every time you made a type mistake (this is the same reason why non-homogenous lists of objects aren't automatically coerced to a union of their types). So you might expect that the following would work: let app_to_mylist (f: 'a list -> 'b) = function Intlist x -> f x | Strlist x -> f x ;; but this doesn't force O'Caml to do anything, it's still free to refine 'a to int or string. (Just like how if you write "let x: 'a = 5", x is still an int). The solution is to use existential types. In a record, you can tell O'Caml that a particular function _must_ be polymorphic: type 'b mylistfun = { listfun: 'a. 'a list -> 'b } Prefixing f's type with "'a." tells O'Caml that 'a is an existential type variable, meaning that f must be able to work with any 'a. Note that 'a doesn't appear in mylistfun's list of type variables (since it would make no sense to choose a type for 'a). So armed with mylistfun, you can rewrite app_to_mylist as: # let app_to_mylist { listfun = f } = function Intlist x -> f x | Strlist x -> f x;; val app_to_mylist : 'a mylistfun -> mylist -> 'a = and all is well: # app_to_mylist { listfun = List.length } (Intlist [1;2;3]);; - : int = 3 Unfortunately this trick only works with records and objects, so you're forced to box up the function before handing it to app_to_mylist. (I forget the reason why you can't do this in general but I'm sure someone else can enlighten us both.) Hope this helps. - Chris