* Problem binding type parameters in modules @ 1999-01-16 12:21 Markus Mottl 1999-01-18 14:59 ` Sylvain BOULM'E 1999-01-19 8:50 ` Problem binding type parameters in modules Hendrik Tews 0 siblings, 2 replies; 6+ messages in thread From: Markus Mottl @ 1999-01-16 12:21 UTC (permalink / raw) To: OCAML Hello, sometimes one has the impression that there must be a simple solution, but one can just not see it... My problem (example code): --------------------------------------------------------------------------- module type FOO1 = sig type 'a foo val empty : 'a foo end module type FOO2 = sig type foo val empty : foo end (* ok *) module Foo1 : FOO1 = struct type 'a foo = 'a list let empty = [] end (* also ok *) module Foo2 : FOO2 = struct type foo = int list Lazy.t let empty = lazy [] end (* not ok *) module Bar : FOO1 = struct type 'a foo = 'a list Lazy.t let empty = lazy [] end --------------------------------------------------------------------------- The compiler will report an error, because it does not infer the type of "empty" in module "Bar" as specified in "FOO1". No matter what I have tried, I haven't succeed in binding the type parameter needed in "empty" to "'a" in type "foo", so that the module signatures would match. E.g.: --------------------------------------------------------------------------- (* also not ok *) module Bar : FOO1 = struct type 'a foo = 'a list Lazy.t let empty : 'a foo = lazy [] end --------------------------------------------------------------------------- The "'a" specified in "empty" is still not the same as in "'a foo". I have not yet tried to use a functor to bind the function to the correct type, but I think this should not be necessary. As one can see in the example, the type of "empty" is correctly inferred in "Foo1" and "Foo2". I do not understand, why the compiler does not do so in the last case. Am I overlooking any easy way out? Or is this even a bug? Best regards, Markus Mottl -- Markus Mottl, mottl@miss.wu-wien.ac.at, http://miss.wu-wien.ac.at/~mottl ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Problem binding type parameters in modules 1999-01-16 12:21 Problem binding type parameters in modules Markus Mottl @ 1999-01-18 14:59 ` Sylvain BOULM'E 1999-01-18 17:07 ` Problem binding type parameters in modules + subtyping and inheritance Markus Mottl 1999-01-19 8:50 ` Problem binding type parameters in modules Hendrik Tews 1 sibling, 1 reply; 6+ messages in thread From: Sylvain BOULM'E @ 1999-01-18 14:59 UTC (permalink / raw) To: Markus Mottl; +Cc: caml-list Hello !! The problem you mentionned, comes from the type rule of O'Caml : "there is a the type generalization ONLY on values..." For exemple (as an application is not a value), In the environnement : module type FOO1 = sig type 'a foo val empty : 'a foo end;; let id x = x;; The following definition fails to typecheck : module Bar : FOO1 = struct type 'a foo = 'a list let empty = id [];; end;; This restritriction has been made to deals with "polymorphic references". Indeed, without this restriction the following lines success to typecheck : let empty = ref [];; let push x = empty:=x::!empty;; (push 1);; (push true);; which shows that there is no typesystem any more. so in "let empty=ref []", empty has type '_a list ref where the "_" in the "'_a" means that "'_a" could be instanced only once. Actually, the restriction may seems a bit strong, but it seems difficult to decide if an expression should be polymorphic or not.... To solve your problem, you may use functors: module type FOO1 = functor (M:sig type elt end) -> sig type foo val empty : foo end;; module Bar: FOO1 = functor (M:sig type elt end) -> struct type foo = M.elt list let empty = id [];; end;; ----------------------------------------------------------- The main drawback about your propositions in "subtyping and inheritance - correction", is the semantic of methods becomes very hard to understand (because it depends on the context). It is already not easy to understand the difference between subtyping and polymorphism on objects, but actually you don't care, because it doesn't affect the behaviour of methods (you may only have difficulties to typecheck). Best regards. Sylvain ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Problem binding type parameters in modules + subtyping and inheritance 1999-01-18 14:59 ` Sylvain BOULM'E @ 1999-01-18 17:07 ` Markus Mottl 1999-01-18 19:16 ` Jerome Vouillon 0 siblings, 1 reply; 6+ messages in thread From: Markus Mottl @ 1999-01-18 17:07 UTC (permalink / raw) To: Sylvain BOULM'E; +Cc: OCAML Hello, > This restritriction has been made to deals with "polymorphic references". > Indeed, without this restriction the following lines success to typecheck : > let empty = ref [];; > let push x = empty:=x::!empty;; > (push 1);; > (push true);; > which shows that there is no typesystem any more. Ah, I see! A not very attractive outcome, indeed... > so in "let empty=ref []", empty has type '_a list ref where the "_" in the > "'_a" means that "'_a" could be instanced only once. > > Actually, the restriction may seems a bit strong, but it seems difficult to > decide if an expression should be polymorphic or not.... > > To solve your problem, you may use functors: > > module type FOO1 = functor (M:sig type elt end) -> > sig > type foo > val empty : foo > end;; > > module Bar: FOO1 = functor (M:sig type elt end) -> > struct > type foo = M.elt list > let empty = id [];; > end;; I already feared that this would be necessary. Not that I would have anything against functors, but I am porting Okasaki's "Purely Functional Data Structures" from SML to OCAML (already half way through) and I would really like to stick as close as possible to his code: I.e. if he doesn't use a functor with some module, I think it is easier for the OCAML-programming readers of his book if I do the same. The differences in the module systems are in general very small. It is only necessary in OCAML to use the "with"-keyword as in "HEAP with module Elem = Element" in the restriction of module interfaces so that the programmer can access elements with the right type. But this does not effect the rest of the code. I think that these explicit declarations make things clearer and are more exact from a formal point of view. So I prefer the OCAML-style in this case. Since Okasaki's code contains parts with annotations for lazy evaluation (just a demonstration - SML does not have this), I used OCAML's "Lazy" module - hence the problem with polymorphic use of "lazy" in modules. It actually works great - the code adaptions are not really a problem, because the type checker very accurately points to expressions, where laziness has been used in a wrong way or forgotten. I will begin to make the translations freely available soon - before that I will have to ask the author about potential violations of copyrights, but I believe this will not be a problem (his SML- and Haskell-sources are also free for download). > ----------------------------------------------------------- > > The main drawback about your propositions in "subtyping and inheritance - > correction", is the semantic of methods becomes very hard to understand > (because > it depends on the context). It is already not easy to understand the difference > between subtyping and polymorphism on objects, but actually you don't care, > because > it doesn't affect the behaviour of methods (you may only have difficulties to > typecheck). Yes, I see that semantics can be more of a problem in this case. On the other hand (I am a burned child), some properties of inheritance together with the "'self"-type can really be annoying: There just has to be a single, innocent looking class with the "'self"-type at the top of the inheritance hierarchie and it is impossible to coerce any of its descendants to any ancestor in the same line. The problem here is that it is absolutely not evident (syntactically) in the child classes that one of its ancestors has this property - and that it will pass it on like a disease. A poor programmer might have to walk through the whole class hierarchie, just to find out that his design won't work, because his classes are infected by some other class with the "'self"-type. Things like putting objects of different classes sharing a common subtype in lists become impossible if you want the generic properties of the "'self"-type (automatic instantiation of methods with the corresponding type). I am really not sure whether the tradeoff in losing comprehensibility in terms of semantics is so big that it outweighs potential benefits in the design of class hierarchies. At least I will probably restrict myself from using the "'self"-type, because its effects on design questions appear to me not understandable enough. Though, this will not solve all problems. I will have to invent new names for all methods that (from a semantic point of view) do the same thing - e.g. compare the object with anotherone of the same class. Who knows? - Maybe there is a completely different approach to this. One, which would solve all our problems (my next one is making dinner - God is the refrigerator empty again!) ;-) Best regards, Markus -- Markus Mottl, mottl@miss.wu-wien.ac.at, http://miss.wu-wien.ac.at/~mottl ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Problem binding type parameters in modules + subtyping and inheritance 1999-01-18 17:07 ` Problem binding type parameters in modules + subtyping and inheritance Markus Mottl @ 1999-01-18 19:16 ` Jerome Vouillon 1999-01-18 20:37 ` Markus Mottl 0 siblings, 1 reply; 6+ messages in thread From: Jerome Vouillon @ 1999-01-18 19:16 UTC (permalink / raw) To: Markus Mottl; +Cc: OCAML Hello, > > To solve your problem, you may use functors: > > > > module type FOO1 = functor (M:sig type elt end) -> > > sig > > type foo > > val empty : foo > > end;; > > > > module Bar: FOO1 = functor (M:sig type elt end) -> > > struct > > type foo = M.elt list > > let empty = id [];; > > end;; Another solution is to turn "empty" into a function : module type FOO1 = sig type 'a foo val empty : unit -> 'a foo end;; module Bar : FOO1 = struct type 'a foo = 'a list Lazy.t let empty () = lazy [] end;; ----------------------------------------------------------- > There just has to be a single, innocent looking class with the > "'self"-type at the top of the inheritance hierarchie and it is impossible > to coerce any of its descendants to any ancestor in the same line. Actually, it is still possible to make the coercion when the type of self only occur in covariant position (in particular, only on the right sides of arrows) : class c = object (self) method m = self end;; class d = object (self) inherit c method n = 1 end;; let x = (new d :> c);; There is a difficulty with "binary methods", where self type occurs in contravariant position : class c = object (self : 'a) method x = 1 method compare (o : 'a) = self#x = o#x end;; class d = object inherit c method y = 1 end;; let x = (new d :> c);; (* Fails *) However, you can coerce to a common supertype of c and d which has no method "compare" : class type c' = object method x : int end;; let l = [(new c :> c'); (new d :> c')];; (* Succeeds *) -- Jérôme ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Problem binding type parameters in modules + subtyping and inheritance 1999-01-18 19:16 ` Jerome Vouillon @ 1999-01-18 20:37 ` Markus Mottl 0 siblings, 0 replies; 6+ messages in thread From: Markus Mottl @ 1999-01-18 20:37 UTC (permalink / raw) To: Jerome Vouillon; +Cc: OCAML Hello, > Another solution is to turn "empty" into a function : > module type FOO1 = sig > type 'a foo > val empty : unit -> 'a foo > end;; > module Bar : FOO1 = struct > type 'a foo = 'a list Lazy.t > let empty () = lazy [] > end;; Would certainly also work. But I guess it is better to stay with the functor - modules parameterized with a new value are not so common as function invocations. Thus, I won't have to change this much code porting Okasaki's sources. > ----------------------------------------------------------- > Actually, it is still possible to make the coercion when the type of > self only occur in covariant position (in particular, only on the > right sides of arrows) : > class c = object (self) > method m = self > end;; > class d = object (self) > inherit c > method n = 1 > end;; > let x = (new d :> c);; > > There is a difficulty with "binary methods", where self type occurs in > contravariant position : > class c = object (self : 'a) > method x = 1 > method compare (o : 'a) = self#x = o#x > end;; > class d = object > inherit c > method y = 1 > end;; > let x = (new d :> c);; (* Fails *) Unfortunately, it's the binary methods I need... > However, you can coerce to a common supertype of c and d which has no > method "compare" : > class type c' = object > method x : int > end;; > let l = [(new c :> c'); (new d :> c')];; (* Succeeds *) That's the problem: Actually the only method I would need is "compare" ;-) Regards, Markus -- Markus Mottl, mottl@miss.wu-wien.ac.at, http://miss.wu-wien.ac.at/~mottl ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Problem binding type parameters in modules 1999-01-16 12:21 Problem binding type parameters in modules Markus Mottl 1999-01-18 14:59 ` Sylvain BOULM'E @ 1999-01-19 8:50 ` Hendrik Tews 1 sibling, 0 replies; 6+ messages in thread From: Hendrik Tews @ 1999-01-19 8:50 UTC (permalink / raw) To: caml-list Hi, My problem (example code): [omitted] What about using abstraction? eg module type FOO1 = sig type 'a foo val empty : unit -> 'a foo end module Bar : FOO1 = struct type 'a foo = 'a list Lazy.t let empty () = lazy [] end Then empty is a function and its type gets generelized. The "'a" specified in "empty" is still not the same as in "'a foo". I have The section about type checking in the list of "Frequently asked Questions about Caml" (http://caml.inria.fr/FAQ/FAQ_EXPERT-eng.html) explains the differences between 'a and '_a. Bye, Hendrik ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~1999-01-19 16:55 UTC | newest] Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 1999-01-16 12:21 Problem binding type parameters in modules Markus Mottl 1999-01-18 14:59 ` Sylvain BOULM'E 1999-01-18 17:07 ` Problem binding type parameters in modules + subtyping and inheritance Markus Mottl 1999-01-18 19:16 ` Jerome Vouillon 1999-01-18 20:37 ` Markus Mottl 1999-01-19 8:50 ` Problem binding type parameters in modules Hendrik Tews
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox