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 82B8B7FB5F for ; Thu, 22 Oct 2015 16:54:53 +0200 (CEST) IronPort-PHdr: 9a23:6eVcexHZFGUQth3F/7gfip1GYnF86YWxBRYc798ds5kLTJ75pc+wAkXT6L1XgUPTWs2DsrQf27eQ6/yrCTVIyK3CmU5BWaQEbwUCh8QSkl5oK+++Imq/EsTXaTcnFt9JTl5v8iLzG0FUHMHjew+a+SXqvnYsExnyfTB4Ov7yUtaLyZ/niqbqp9aDOk1hv3mUX/BbFF2OtwLft80b08NJC50a7V/3mEZOYPlc3mhyJFiezF7W78a0+4N/oWwL46pyv50IbaKvZKk8TLtACykOPGU85cmtvh7GHiWV4X5JdWEbnVIcBAzI4zn9XZLwsG39rOUri3rSBtH/Ub1hAWfq1KxsUhK90Co= Authentication-Results: mail2-smtp-roc.national.inria.fr; spf=None smtp.pra=oleg@okmij.org; spf=Pass smtp.mailfrom=oleg@okmij.org; spf=None smtp.helo=postmaster@mail1.g3.pair.com Received-SPF: None (mail2-smtp-roc.national.inria.fr: no sender authenticity information available from domain of oleg@okmij.org) identity=pra; client-ip=66.39.3.114; receiver=mail2-smtp-roc.national.inria.fr; envelope-from="oleg@okmij.org"; x-sender="oleg@okmij.org"; x-conformance=sidf_compatible Received-SPF: Pass (mail2-smtp-roc.national.inria.fr: domain of oleg@okmij.org designates 66.39.3.114 as permitted sender) identity=mailfrom; client-ip=66.39.3.114; receiver=mail2-smtp-roc.national.inria.fr; envelope-from="oleg@okmij.org"; x-sender="oleg@okmij.org"; 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@mail1.g3.pair.com) identity=helo; client-ip=66.39.3.114; receiver=mail2-smtp-roc.national.inria.fr; envelope-from="oleg@okmij.org"; x-sender="postmaster@mail1.g3.pair.com"; x-conformance=sidf_compatible X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: A0BxAABl+ChWnHIDJ0JexHuGHQKBRDwQAQEBAQEBAQEQAQEBAQEICwkJIS6CJ4IIAQEDAScTPwUWITQFd4gNCMU5AQEBBwIBIIt1hQ0HF4MDgRQFjgiII4FSi0QIgxeZDziCUoFrhyYBAQE X-IPAS-Result: A0BxAABl+ChWnHIDJ0JexHuGHQKBRDwQAQEBAQEBAQEQAQEBAQEICwkJIS6CJ4IIAQEDAScTPwUWITQFd4gNCMU5AQEBBwIBIIt1hQ0HF4MDgRQFjgiII4FSi0QIgxeZDziCUoFrhyYBAQE X-IronPort-AV: E=Sophos;i="5.20,182,1444687200"; d="scan'208";a="184044802" Received: from mail1.g3.pair.com ([66.39.3.114]) by mail2-smtp-roc.national.inria.fr with ESMTP/TLS/ADH-AES256-GCM-SHA384; 22 Oct 2015 16:54:33 +0200 Received: from Magus.sf-private (fortigate.sf.ecei.tohoku.ac.jp [130.34.188.206]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail1.g3.pair.com (Postfix) with ESMTPSA id A51A934AA4; Thu, 22 Oct 2015 10:54:30 -0400 (EDT) Date: Fri, 23 Oct 2015 00:04:30 +0900 From: Oleg To: seliopou@gmail.com Cc: caml-list@inria.fr Message-ID: <20151022150430.GA2917@Magus.sf-private> Mail-Followup-To: Oleg , seliopou@gmail.com, caml-list@inria.fr MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.22 (2013-10-16) Subject: Re: [Caml-list] "map"-ing parameterized class types The question was about creating a class of the following type > class type ['a] container : 'a -> > object > method map : 'b. ('a -> 'b) -> 'b container > end with a mapping method that makes a container of a different type. Jeremy Yallop has explained very well the class of exactly such type is not possible. The following is perhaps the simplest workaround requiring neither modules nor other higher-class artillery. It should have been possible even in OCaml 3.10 or earlier. The idea was inspired by some high-falutin' Math, namely, left Kan extension from Category Theory. I actually don't know CT but I think I got the gist of the left Kan extension: rather than execute an an operation, just collect all the needed arguments and declare the operation performed. The recent paper on Freer monads (Haskell Symposium 2015) used two instances of this new kind of laziness. Here is the whole solution type 'a cont_proxy = P of 'a class ['a] container (x : 'a) = object method get_x = x method map' : 'b. ('a -> 'b) -> 'b cont_proxy = fun f -> P (f x) end The class container has one argument, which is the value needed to construct the container. The data type cont_proxy contains all the information needed to construct the container, but not the container itself (for one, the container type is not yet defined when we declared P). The method map' doesn't actually construct anything; it merely returns the data needed for the construction. The map itself is then easy to define: let map : ('a -> 'b) -> ('a container -> 'b container) = fun f c -> match c#map' f with P x -> new container x let c = new container 3 val c : int container = let _ = c#get_x - : int = 3 let c' = map string_of_int c val c' : string container = let _ = c'#get_x - : string = "3"