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 p4F966QJ019258 for ; Sun, 15 May 2011 11:06:06 +0200 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AsMAAOCWz02LEwExe2dsb2JhbACmFRQBARYmBSCIcLMIAYx7BYMVgwSfDA X-IronPort-AV: E=Sophos;i="4.64,368,1301868000"; d="scan'208";a="99060186" Received: from hera.mpi-sb.mpg.de ([139.19.1.49]) by mail4-smtp-sop.national.inria.fr with ESMTP/TLS/AES256-SHA; 15 May 2011 11:06:00 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mpi-sb.mpg.de; s=mail200803; h=From:To:In-Reply-To:Subject: References:Message-Id:Content-Type:Content-Transfer-Encoding: Mime-Version:Date:Cc; bh=7pPSHsxPH2xoUpBAyK7fTFkT9B6fgsHDkBIHAOI 0O1U=; b=PRiZClH5Q9lEC/0AUxPOzhgWoeRI4nTgRfbguywjuDBCGUAovY+DXUN TY+qU/1JZkZxHxq+3rfGmaXW7n310Pu/Pr1X8IAWw+zWDrBmi5EZkcJdOya0h9lU iXXJWxTmfWgLkzv5K29/KnsH1k01Jt0JGbnET74AaTAybuN3yfC4= Received: from infao0525.mpi-klsb.mpg.de ([139.19.1.26]:51335 helo=maniac.mpi-klsb.mpg.de) by hera.mpi-sb.mpg.de (envelope-from ) with esmtp (Exim 4.69) id 1QLXGa-0006dp-9k; Sun, 15 May 2011 11:05:38 +0200 Received: from mnch-5d8675fe.pool.mediaways.net ([93.134.117.254]:53245 helo=[192.168.178.31]) by maniac.mpi-klsb.mpg.de (envelope-from ) with esmtpsa (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.69) id 1QLXGZ-0006Hl-KO; Sun, 15 May 2011 11:05:35 +0200 From: Andreas Rossberg To: Lucas Dixon In-Reply-To: References: <1CD0C5CF-4339-4365-A05C-58A12EE7AE2D@mpi-sws.org> Message-Id: <2F01B4AD-D6F2-4503-8F27-C87ECAC987E1@mpi-sws.org> Content-Type: text/plain; charset=US-ASCII; format=flowed; delsp=yes Content-Transfer-Encoding: 7bit Mime-Version: 1.0 (Apple Message framework v936) Date: Sun, 15 May 2011 11:05:34 +0200 Cc: caml-list List X-Mailer: Apple Mail (2.936) Subject: [Caml-list] Re: functors and modules (was "What is an applicative functor?") On May 11, 2011, at 15.11 h, Lucas Dixon wrote: >>> Here's a better presentation of the idea: >>> >>> http://informallyabstract.blogspot.com/2011/04/typed-signature-variables-for.html >>> [...] >>> I'd like to treat S1 as a signature variable... see blog post linked >>> above. >> >> Sorry, I still don't get it. > > Probably my fault, the post had some typos :( I think I've fixed them > now, as well as swapped the signature ordering, which makes more sense > now: more stuff = bigger. OK, after reading it again, I'm afraid I still have more questions than answers: ;) - What do you mean by "typed signature variables"? In what sense are ML's signature identifiers not variables, or not typed? Also, it seems that all your examples are easily expressible with existing language features, such as `include'. Consequently, I'm somewhat confused what exactly you are trying to achieve. - I don't understand the semantics of your =: operator. AFAICS, the most specific signature of M1 is not S1, but "S1 with type T = int". (But even that depends on the details of the type system. If you had, for example, something akin to SML'90's structure sharing, then the most specific signature of M1 would, in fact, be the singleton M1.) - It seems you want to express a form of mixin composition with your + operator, but you gloss over what the binding structure should be. That is, you seem to expect being able to say S1 + S2, where S2 arbitrarily refers to members from S1. How is that supposed to work? (And would it differ from our `with' operator in MixML?) - Similarly, where do you express the dependency between argument and result in a functor signature? S1 -> S1 is not the most specific signature of the identity functor over S1, that would be "(X:S1) -> S1 with type T = X.T" in most ML's. How should I read your "exact" type of F2? >> How can you project S1.t then? > > S1 still has a type/signature, even though it is a variable: it's just > like an extensible record type (which is now signatures are often > implemented). S1 : { type t, ... }. So you can still project out what > you know is in S1. It's just that S1 may have more stuff as well. > > Does that make sense? Not quite. :) I thought S1 is a signature itself? What does S1 : { type t, ... } mean then? >>> functor F (S1 : SIG1) = >>> struct >>> use "submodule1.ML"; >>> use "submodule2.ML"; >>> end; >> >> Yes, but what you _actually_ want is a way to compile the submodules >> separately, which is where the real problem lies. > > Ah, indeed! So we'd perhaps like each file to implicitly be a functor: > > in "submodule1.ML": > > given M1 : SIG1; > val x = M1.f "some argument string"; > ... > > Is this what you're thinking of in terms of a looser module coupling? Depends on what that declaration does. AFAIU, it would still require me to functorize each individual module, just with a different syntax. >>> But! I think a better language for expressing signatures can >>> easily fix >>> this. >>> e.g. we should be able to write: >>> >>> MAP = { ... } >>> SIG2A = { Map : SIG1 ... } >>> SIG2B = { Map : SIG1 ... } >>> SIG3A = { >>> Map : MAP; >>> S2a : SIG2A where S2a.Map := Map; >>> S2b : SIG2B where S2a.Map := Map; >>> ... } >>> >>> Having structure/signature level substitutions seems to naturally >>> fix >>> this: you now check a single Map at the top level, and modify all >>> types in S2a to refer to those in the parent structure. This also >>> cleans up the many occurrences of the same structure: I'm assuming >>> that S2a.Map no longer exists after you write S2a.Map := ..., >>> instead >>> just have the single top-level Map. Maybe ":=" is not the best >>> syntax... but I think you get the idea. >> >> You actually have that in OCaml 3.12, with almost exactly your >> syntax. But >> your idiom again implements a form of flattening that will pollute >> the >> namespace of the signature's toplevel, and I think can still grow >> exponentially, just with a smaller constant factor. > > I don't think it grows exponentially: Map does not exist in S2a or > S2b. > I also don't think it is a form of name-space pollution. You need to > have some syntax for Map, so it has to live somewhere. Or maybe I'm > missing something? What this feature buys you is that you can eliminate duplicates from your dependencies. That is, you actually get to represent your dependency graph in the signature as a DAG instead of a tree with copies. But you still potentially include that whole dependency graph in every signature. >> I think there is no general solution. Specifying the signatures of >> arbitrary >> slices through a complex software architecture will produce ugly, >> big and >> complex signatures. That's why I don't want to be forced to do it >> everywhere. I only want to specify signatures at suitable package >> boundaries, where I expect looser coupling than within. Within a >> package, I >> just want to use other modules of the same package without >> (explicitly) >> reiterating their signature at every import edge. I.e., writing >> functors is >> not what I want there. > > This sounds to me like just putting things in a global name-space, and > having a hierarchy of uses. I agree that this is useful, but isn't > this just avoiding the act of modularity altogether? I guess I'm > misunderstanding something. Maybe an small example would clarify? Well, small examples are difficult with this topic. A module for me, typically, is an individual ADT. More generally, you can have modules with several abstract types, or cases with none, but the ADT is the essence of small-scale modularity. But a module is not a library. A library (or package, or whatever term you prefer), is a collection of modules that are interdependent and closely related in terms of functionality as well as implementation. Building applications (or other libraries) from libraries is large- scale modularity. I don't think it's useful trying to turn every individual module into a stand-alone library -- which is what always functorizing amounts to. >>> But when you specify a signature, you don't have to specify >>> everything >>> it has, only a super-set of what you use, I can't see how you could >>> get away with less and maintain checking of module compositions... >>> actually I'm not sure I'm understanding this point, maybe you can >>> expand on it a bit? >> >> Does my explanation above answer it? > > Perhaps; but I think I might be misunderstanding, it seems that you're > suggesting just using the top-level to place background libraries. I > think this is often sensible, but this seems independent of having a > module system. So I suspect you're thinking of something else... ? Yes: I simply want to parameterize libraries as a whole over their library dependencies, with as little fuzz as possible. At the level of individual modules, I want to use functors only where I need genericity. The ML module system is great for the latter, but currently not very useful for the former, i.e., it wasn't designed as a package system. Cheers, /Andreas