From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Original-To: caml-list@sympa.inria.fr Delivered-To: caml-list@sympa.inria.fr Received: from mail2-relais-roc.national.inria.fr (mail2-relais-roc.national.inria.fr [192.134.164.83]) by sympa.inria.fr (Postfix) with ESMTPS id 16E507EC6E for ; Sun, 8 Dec 2013 02:15:39 +0100 (CET) Received-SPF: None (mail2-smtp-roc.national.inria.fr: no sender authenticity information available from domain of yallop@gmail.com) identity=pra; client-ip=209.85.212.182; receiver=mail2-smtp-roc.national.inria.fr; envelope-from="yallop@gmail.com"; x-sender="yallop@gmail.com"; x-conformance=sidf_compatible Received-SPF: Pass (mail2-smtp-roc.national.inria.fr: domain of yallop@gmail.com designates 209.85.212.182 as permitted sender) identity=mailfrom; client-ip=209.85.212.182; receiver=mail2-smtp-roc.national.inria.fr; envelope-from="yallop@gmail.com"; x-sender="yallop@gmail.com"; x-conformance=sidf_compatible; x-record-type="v=spf1" Received-SPF: None (mail2-smtp-roc.national.inria.fr: no sender authenticity information available from domain of postmaster@mail-wi0-f182.google.com) identity=helo; client-ip=209.85.212.182; receiver=mail2-smtp-roc.national.inria.fr; envelope-from="yallop@gmail.com"; x-sender="postmaster@mail-wi0-f182.google.com"; x-conformance=sidf_compatible X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: ArsCAN7Ho1LRVdS2lGdsb2JhbABZhAYMgn+2FIEPCBYOAQEBAQcLCwkSKoIlAQEEASMEGQEbHQEDAQsGBQsDCgICJgICIQEBEQEFARwGE4dvAQMJBqUVjAZTgwmDZQoZJw1khgMRAQUMgR2LVIITB4JrgUgDkxWBHIF4gWuMWoNMGCmEVTw X-IPAS-Result: ArsCAN7Ho1LRVdS2lGdsb2JhbABZhAYMgn+2FIEPCBYOAQEBAQcLCwkSKoIlAQEEASMEGQEbHQEDAQsGBQsDCgICJgICIQEBEQEFARwGE4dvAQMJBqUVjAZTgwmDZQoZJw1khgMRAQUMgR2LVIITB4JrgUgDkxWBHIF4gWuMWoNMGCmEVTw X-IronPort-AV: E=Sophos;i="4.93,849,1378850400"; d="scan'208";a="47579361" Received: from mail-wi0-f182.google.com ([209.85.212.182]) by mail2-smtp-roc.national.inria.fr with ESMTP/TLS/RC4-SHA; 08 Dec 2013 02:15:38 +0100 Received: by mail-wi0-f182.google.com with SMTP id en1so2327402wid.15 for ; Sat, 07 Dec 2013 17:15:38 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :cc:content-type; bh=dJRNc3iFfYWnXtMnMV5hymEvrj8G3mUAH9oAX4+Kb6g=; b=MnAsTVYRzjsJ6Rxp32B+wSCiFKNUqHH9we1uiHhwOLPBveEe+UJplUtvuOW0Afyrk0 VfEyZt+CWEu6csWbpQYphpvDApkECZRGjJWouxrYpwmBRPqAeuXMGlaIAWd9DxzkQ986 9AKJIcFxXFxZHG78bgR/inXFJPp8lmNwVPTC/kZjt2AiSUt4P1P8RaRCLJyR1T0RbE5f pQR98dxE7x56RVZV8ed3Ql6Ezip1BgFekYOFrV5edNgfZnURoMf4oAtk2PCXlMuSES92 NWwSRKEKWhhDKJloGSibfcGUI0Tjjp4abGFZKU811ev7WlT8CF3qBCGvt8ECjQYA7nzx Anjg== MIME-Version: 1.0 X-Received: by 10.194.89.233 with SMTP id br9mr9448639wjb.15.1386465338215; Sat, 07 Dec 2013 17:15:38 -0800 (PST) Received: by 10.216.33.4 with HTTP; Sat, 7 Dec 2013 17:15:38 -0800 (PST) In-Reply-To: <529E198F.7060704@gmail.com> References: <529BAB43.3080105@gmail.com> <529D97B4.9070108@frisch.fr> <529DCF8A.2040308@frisch.fr> <529E198F.7060704@gmail.com> Date: Sun, 8 Dec 2013 01:15:38 +0000 Message-ID: From: Jeremy Yallop To: Dmitri Boulytchev Cc: Alain Frisch , caml-list Content-Type: text/plain; charset=UTF-8 Subject: Re: [Caml-list] Confusing behaviour of type inference for polymorphic classes. On 3 December 2013 17:49, Dmitri Boulytchev wrote: > Here subm is a legitimate subclass of m with the desired behaviour [...]. So I don't see why I'm loosing the ability to subtype. You're quite right, of course: you still have subtyping. What you're giving up are some of the benefits of inheritance, since the "recursive" calls go through the instance you pass in rather than through a self variable. If you don't have other reasons for using objects and classes it might be worth considering using records instead, since they're semantically much simpler. The example should translate directly: type ('a, 'b, 'ta, 'tb) m' = { t : ('a -> 'ta) -> ('b -> 'tb) -> ('a, 'b) t -> ('ta, 'tb) t } let proto_m f = { t = fun fa fb s -> ... let m' f = let super = proto_m f in { super with t = fun fa fb s -> ... > It seems to me that this workaround can be used to overcome the "regular class" restriction completely in a syntax-conversion manner. I appreciate any comments. Yes, it's a neat approach! One small suggestion: in order to handle the case where the type you're traversing has multiple recursive instantations with different parameters you might consider passing the instance creation function in a way that allows it to be called polymorphically (e.g. by wrapping it in a record with a polymorphic field): type new_proto_m = { new_proto_m : 'a 'b 'ta 'tb . unit -> 'ta) -> ('b -> 'tb) -> ('a, 'b) t -> ('ta, 'tb) t> } There is one last thing I'm curious about. The difficulties that you're avoiding with open recursion seem to arise from the representation of the traversal as a parameterised class with a monomorphic method. Have you considered switching things round and using an unparameterised class with polymorphic methods instead? I think everything turns out much simpler if you do: you can use straightforward inheritance, calls through self, etc. class m = object (self) method t : 'a 'b 'ta 'tb. ('a -> 'ta) -> ('b -> 'tb) -> ('a, 'b) t -> ('ta, 'tb) t = fun fa fb s -> match s with | A (a, bat) -> A (fa a, self#t fb fa bat) | B a -> B (fa a) end The map and fold generators supplied with Camlp4 use a variant of this approach, and it seems to work well in practice.