* [Caml-list] polymorphic method question
@ 2002-08-21 21:49 nadji
2002-08-21 22:57 ` Jacques Garrigue
0 siblings, 1 reply; 12+ messages in thread
From: nadji @ 2002-08-21 21:49 UTC (permalink / raw)
To: caml-list
Hi,
I am puzzled by this behaviour, can a guru explain me ?
I have two classes
class type ['a] basic = object
method foo : 'a
end;;
class ['a] toto (a:'a) = object
method foo = a
method bar = ()
end;;
I want to do a class gentoto :
class gentoto = object
method gen : 'a . 'a -> 'a basic =
fun x -> (new toto x :> 'a basic )
end;;
But the compiler complains that :
Characters 64-98:
fun x -> (new toto x :> 'a basic )
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This method has type 'a -> 'a basic which is less general than
'b. 'b -> 'b basic
... but if I do :
let newtotoasbasic x = (new toto x :> 'a basic );;
class gentoto =
object
method gen : 'a . 'a -> 'a basic =
(* fun x -> (new toto x :> 'a basic ) *)
newtotoasbasic
end;;
The compiler agrees with me ...
What is wrong with the first declaration ?
Thanks,
Nadji
-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Caml-list] polymorphic method question
2002-08-21 21:49 [Caml-list] polymorphic method question nadji
@ 2002-08-21 22:57 ` Jacques Garrigue
0 siblings, 0 replies; 12+ messages in thread
From: Jacques Garrigue @ 2002-08-21 22:57 UTC (permalink / raw)
To: nadji; +Cc: caml-list
From: nadji@noos.fr
> I am puzzled by this behaviour, can a guru explain me ?
> I have two classes
[...]
> I want to do a class gentoto :
> class gentoto = object
> method gen : 'a . 'a -> 'a basic =
> fun x -> (new toto x :> 'a basic )
> end;;
> But the compiler complains that :
> Characters 64-98:
> fun x -> (new toto x :> 'a basic )
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> This method has type 'a -> 'a basic which is less general than
> 'b. 'b -> 'b basic
>
> ... but if I do :
> let newtotoasbasic x = (new toto x :> 'a basic );;
[...]
> The compiler agrees with me ...
> What is wrong with the first declaration ?
There is a problem with the scoping of named type variables in the
language, which makes them incompatible with polymorphic methods.
You can solve this by using anonymous variables:
# class gentoto = object
method gen : 'a . 'a -> 'a basic =
fun x -> (new toto x :> _ basic)
end;;
class gentoto : object method gen : 'a -> 'a basic end
Jacques Garrigue
-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Caml-list] Polymorphic method question
2006-07-12 0:37 ` Jacques Garrigue
@ 2006-07-12 19:26 ` brogoff
0 siblings, 0 replies; 12+ messages in thread
From: brogoff @ 2006-07-12 19:26 UTC (permalink / raw)
To: Jacques Garrigue; +Cc: caml-list
On Wed, 12 Jul 2006, Jacques Garrigue wrote:
> From: brogoff <brogoff@speakeasy.net>
> > > I'm sure you need some tricks to make it work in Java 1.5 too.
> >
> > The nastiest one for Caml is a downcast, when you want to extend the data
> > the new class must call the extended visitor in its visit method. But Java
> > supports this, so no big deal.
>
> Well, if you're ready to have downcasts in your code...
> But then,
I'd hoped that there would be some trick I could figure out to remove the
downcast, but it's essentially to overcome the lack of covariant
method arguments (the visitor argument of the visited class) so yes it's a
flaw in the approach.
> I would not say that your Java version is more "typed". It is less so
> if you have downcasts!
Fair enough. However, the "typecase" that's being performed has only one branch,
and is localized to the extending class, so as such crimes go, it's more
like vandalism than arson.
> [About having to write the type hierarchy by hand]
> > But we have to repeat the information from the type in a later class,
> > which seems redundant. Also, there's no way I know of to build object types
> > from other object types, similar to the way I can combine polymorphic variant
> > types.
> >
> > I haven't tried to encode it yet, maybe I'll try later, but I don't
> > see how it can be made to work.
>
> Indeed. At times I wonder whether it would not be better to have a
> syntax to do this with types. Or maybe not to infer parameter
> constraints for class types, as they are required for extensibility.
I think if we're going to do OO in an ML like language, I think it is probably
more promising to consider a system like Dylan or CLOS. But that's a huge
change, for a brand new language.
I'd rather have a simpler language, with more powerful records, variants and
module system. I usually use classes in OCaml as records anyways.
-- Brian
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Caml-list] Polymorphic method question
2006-07-11 18:20 ` brogoff
@ 2006-07-12 0:37 ` Jacques Garrigue
2006-07-12 19:26 ` brogoff
0 siblings, 1 reply; 12+ messages in thread
From: Jacques Garrigue @ 2006-07-12 0:37 UTC (permalink / raw)
To: brogoff; +Cc: caml-list
From: brogoff <brogoff@speakeasy.net>
> > I'm sure you need some tricks to make it work in Java 1.5 too.
>
> The nastiest one for Caml is a downcast, when you want to extend the data
> the new class must call the extended visitor in its visit method. But Java
> supports this, so no big deal.
Well, if you're ready to have downcasts in your code...
But then,
> > Note that, if you are ready to use a slightly less functional
> > approach, where the result is extracted from the visitor afterwards,
> > then typing is no problem.
>
> That's probably the right way to proceed, namely to eliminate the
> problem by eliminating the polymorphic methods. Too bad, the Java
> solution is both more functional, and more "typed". One of those
> rare cases for me where I feel that the Java solution is more
> elegant than the OCaml one.
I would not say that your Java version is more "typed". It is less so
if you have downcasts!
By the way, the Scala version I mentioned uses no downcast, but cannot
accomodate polymorphic methods (at least in the mentioned paper.)
So there seems to be a tension between guaranteed type-safety and
immutability. The point is that to solve it cleanly, one has to use type
parameters in an abstract type. OCaml is able to do it, but I agree
that this is rather verbose.
[About having to write the type hierarchy by hand]
> But we have to repeat the information from the type in a later class,
> which seems redundant. Also, there's no way I know of to build object types
> from other object types, similar to the way I can combine polymorphic variant
> types.
>
> I haven't tried to encode it yet, maybe I'll try later, but I don't
> see how it can be made to work.
Indeed. At times I wonder whether it would not be better to have a
syntax to do this with types. Or maybe not to infer parameter
constraints for class types, as they are required for extensibility.
Jacques Garrigue
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Caml-list] Polymorphic method question
2006-07-11 7:32 ` Jacques Garrigue
@ 2006-07-11 18:20 ` brogoff
2006-07-12 0:37 ` Jacques Garrigue
0 siblings, 1 reply; 12+ messages in thread
From: brogoff @ 2006-07-11 18:20 UTC (permalink / raw)
To: Jacques Garrigue; +Cc: caml-list
On Tue, 11 Jul 2006, Jacques Garrigue wrote:
> From: brogoff <brogoff@speakeasy.net>
> > > By the way, if you're ready to define your types first, then you
> > > can do this properly.
> >
> > In the more realistic example I sent along after, you'll see that this
> > solution is not really pleasing. You'd need to create a parallel type
> > hierarchy to match your class hierarchy, which is too verbose. All this
> > because we must have inference, which is supposed to make things less
> > verbose. Ironic, isn't it? ;-)
>
> I'm not so sure about verbosity. Type syntax is pretty compact :-)
But we have to repeat the information from the type in a later class,
which seems redundant. Also, there's no way I know of to build object types
from other object types, similar to the way I can combine polymorphic variant
types.
I haven't tried to encode it yet, maybe I'll try later, but I don't see how it
can be made to work.
> I'm sure you need some tricks to make it work in Java 1.5 too.
The nastiest one for Caml is a downcast, when you want to extend the data
the new class must call the extended visitor in its visit method. But Java
supports this, so no big deal. Also, Java generics require that primitive
types be wrapped, a mild annoyance. That's about it. Way easier than my
attempts in OCaml, even though I don't use Java much at all. OK, to be fair,
the original paper uses some Java variant (Pizza?) so maybe that's not too
surprising. I wrote the code and it compiled, but I haven't tested it.
> I don't have the code in mind.
> I agree that the solution I posted is not too simple, but I don't
> think this is PhD level. Actually it's not much worse than the visitor
> pattern. What is hard is understanding why you have to do all this
> extra work, not using the pattern itself.
Sure, I exaggerated for affect, but I think the comparison with Java for this
problem is telling.
I'm reminded of something David MacQueen wrote in his paper "Should ML be
Object Oriented" where he says in essence that the functional core of ML
is lightweight and understandable but that OO (from the static typing POV)
is surprisingly subtle and complex.
> Note that, if you are ready to use a slightly less functional
> approach, where the result is extracted from the visitor afterwards,
> then typing is no problem.
> This code is based on http://cristal.inria.fr/~remy/work/expr/
> It is strictly equivalent to Odersky&Zenger's Scala version.
> (Actually this kind of code is one reason we reverted to sharing of
> instance variables in 3.10)
That's probably the right way to proceed, namely to eliminate the
problem by eliminating the polymorphic methods. Too bad, the Java
solution is both more functional, and more "typed". One of those
rare cases for me where I feel that the Java solution is more
elegant than the OCaml one.
-- Brian
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Caml-list] Polymorphic method question
2006-07-11 5:22 ` brogoff
@ 2006-07-11 7:32 ` Jacques Garrigue
2006-07-11 18:20 ` brogoff
0 siblings, 1 reply; 12+ messages in thread
From: Jacques Garrigue @ 2006-07-11 7:32 UTC (permalink / raw)
To: brogoff; +Cc: caml-list
From: brogoff <brogoff@speakeasy.net>
> > The only way to solve this problem would be to remove parameter
> > constraint inference from classes. It would certainly break some
> > programs, so this seems difficult.
>
> That's too bad, as it seems the class based OO version of the extensible
> visitor is fairly straightforward in OCaml except for this counterintuitive
> gotcha. What would have to be done to fix the broken programs? It may be
> worth considering.
You just would have to write constraints explicitly when they are
needed.
This could be a pain for classes. See the tutorial on the
subject-observer pattern in the reference manual for a non-trivial use
of inference.
But maybe we could rather have a way to tell the system that, for some
specific class, type parameters are not constrained. Hacky though.
> > By the way, if you're ready to define your types first, then you
> > can do this properly.
>
> In the more realistic example I sent along after, you'll see that this
> solution is not really pleasing. You'd need to create a parallel type
> hierarchy to match your class hierarchy, which is too verbose. All this
> because we must have inference, which is supposed to make things less
> verbose. Ironic, isn't it? ;-)
I'm not so sure about verbosity. Type syntax is pretty compact :-)
> I have seen the new private rows stuff, which is very nice, but all of these
> solutions IMO are way too complex to be considered satisfactory. I'll see if
> the Java 1.5 approach actually works (I used some Pizza code to do the OCaml
> implementation) because that was quite straightforward. I'd prefer approaches
> that I can explain with a little hand waving. I think type theorists often
> forget that there are a few programmers still who don't have PhDs in type
> theory and will look at such solutions and conclude that OCaml is not for
> them ;-).
I'm sure you need some tricks to make it work in Java 1.5 too.
I don't have the code in mind.
I agree that the solution I posted is not too simple, but I don't
think this is PhD level. Actually it's not much worse than the visitor
pattern. What is hard is understanding why you have to do all this
extra work, not using the pattern itself.
Note that, if you are ready to use a slightly less functional
approach, where the result is extracted from the visitor afterwards,
then typing is no problem.
This code is based on http://cristal.inria.fr/~remy/work/expr/
It is strictly equivalent to Odersky&Zenger's Scala version.
(Actually this kind of code is one reason we reverted to sharing of
instance variables in 3.10)
Jacques Garrigue
module Shape =
struct
class virtual shape_visitor =
object
method virtual visit_square : square -> unit
method virtual visit_rectangle : rectangle -> unit
method virtual visit_polygon : polygon -> unit
method virtual visit_translated : translated -> unit
(* and potentially many more! *)
end
and virtual shape =
object
method virtual visit : shape_visitor -> unit
end
and square pt width =
object (self)
inherit shape
method visit visitor = visitor#visit_square (self :> square)
method as_tuple : ((int * int) * (int * int)) =
let (ll_x, ll_y) = pt in
(pt, (ll_x + width, ll_y + width))
method as_point_list : (int * int) list =
failwith "Shape.square#as_point_list: unimplemented"
end
and rectangle ll ur =
object (self)
inherit shape
method visit visitor = visitor#visit_rectangle (self :> rectangle)
method as_tuple : ((int * int) * (int * int)) = (ll, ur)
method as_point_list : (int * int) list =
failwith "Shape.rectangle#as_point_list: unimplemented"
end
and polygon points =
object (self)
val points : (int * int) list = points
inherit shape
method visit visitor = visitor#visit_polygon (self :> polygon)
method as_point_list : (int * int) list =
points
end
and translated (pt : int * int) (s : shape) =
object (self)
inherit shape
method visit visitor = visitor#visit_translated (self :> translated)
method get_shape = s
method get_translation = pt
method as_point_list : (int * int) list =
failwith "Shape.translated#as_point_list: unimplemented"
end
end (* module Shape *)
module Contains_point =
struct
(* Writing code that works over shapes *)
class contains_point point =
object
inherit Shape.shape_visitor
val mutable result = false
method result = result
method visit_square : Shape.square -> unit =
fun s ->
let ((ll_x, ll_y), (ur_x, ur_y)) = s#as_tuple in
let (x, y) = point in
result <- ll_x <= x && x <= ur_x && ll_y <= y && y <= ur_y
method visit_rectangle : Shape.rectangle -> unit =
fun r ->
let ((ll_x, ll_y), (ur_x, ur_y)) = r#as_tuple in
let (x, y) = point in
result <- ll_x <= x && x <= ur_x && ll_y <= y && y <= ur_y
method visit_polygon : Shape.polygon -> unit =
fun p ->
failwith "Contains_point.contains_point#visit_polygon: unimplemented"
method visit_translated : Shape.translated -> unit =
fun t ->
let (x, y) = point in
let (dx, dy) = t#get_translation in
let visitor = new contains_point (x-dx, y-dy) in
t#get_shape#visit (visitor :> Shape.shape_visitor);
result <- visitor#result
end
let contains_point p (s : #Shape.shape) =
let visitor = new contains_point p in
s#visit (visitor :> Shape.shape_visitor);
visitor#result
end;;
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Caml-list] Polymorphic method question
2006-07-11 2:09 ` Jacques Garrigue
@ 2006-07-11 5:22 ` brogoff
2006-07-11 7:32 ` Jacques Garrigue
0 siblings, 1 reply; 12+ messages in thread
From: brogoff @ 2006-07-11 5:22 UTC (permalink / raw)
To: Jacques Garrigue; +Cc: caml-list
On Tue, 11 Jul 2006, Jacques Garrigue wrote:
> From: brogoff <brogoff@speakeasy.net>
>
> Because bar is not yet completely defined when you use it in foobar.
> This is all related with parameter constraint inference: we don't know
> yet wether bar's parameter is really polymorphic or is constraint (e.g.
> 'a = 'b * 'c).
> Note that the problem does not occur with direct type definitions, as
> constraint inference is not done in that case (this is one of the
> reasons you cannot combine type and class definitions.)
>
> # type 'a bar = < get: 'a > and foobar = < f : 'a. 'a bar -> 'a >;;
> type 'a bar = < get : 'a >
> and foobar = < f : 'a. 'a bar -> 'a >
>
> The only way to solve this problem would be to remove parameter
> constraint inference from classes. It would certainly break some
> programs, so this seems difficult.
That's too bad, as it seems the class based OO version of the extensible
visitor is fairly straightforward in OCaml except for this counterintuitive
gotcha. What would have to be done to fix the broken programs? It may be
worth considering.
> By the way, if you're ready to define your types first, then you
> can do this properly.
In the more realistic example I sent along after, you'll see that this
solution is not really pleasing. You'd need to create a parallel type
hierarchy to match your class hierarchy, which is too verbose. All this
because we must have inference, which is supposed to make things less
verbose. Ironic, isn't it? ;-)
I have seen the new private rows stuff, which is very nice, but all of these
solutions IMO are way too complex to be considered satisfactory. I'll see if
the Java 1.5 approach actually works (I used some Pizza code to do the OCaml
implementation) because that was quite straightforward. I'd prefer approaches
that I can explain with a little hand waving. I think type theorists often
forget that there are a few programmers still who don't have PhDs in type
theory and will look at such solutions and conclude that OCaml is not for
them ;-).
-- Brian
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Caml-list] Polymorphic method question
2006-07-11 2:24 ` skaller
@ 2006-07-11 4:56 ` brogoff
0 siblings, 0 replies; 12+ messages in thread
From: brogoff @ 2006-07-11 4:56 UTC (permalink / raw)
To: skaller; +Cc: caml-list, Richard Jones
On Tue, 11 Jul 2006, skaller wrote:
> On Mon, 2006-07-10 at 16:25 -0700, brogoff wrote:
>
> > The restriction on polymorphism in mutually recursive class
> > definitions makes the idea unworkable. Any possibility that restriction will be
> > lifted?
>
> I don't believe there is such a restriction:
See the thread that Richard referenced, and go to Jacques Garrigue's final post.
There he writes:
"Inside mutually recursive definitions of classes, parameters cannot be
used polymorphically"
That's the problem, isn't it?
> the problem is
> when you introduce other types such as variants which must
> recurse with class types, there's no support for
>
> type class t1 = ..
> and t2 = [`X ..]
That's surely annoying, but it's a different problem I think.
>
> etc. The solution, using extra parameters and open
> recursion, followed by closure of the recursions,
> works but is vastly too messy to encode by hand if there
> are more than a couple of parameters needed. This really
> does need to be automated in the special case where
> you're only opening the types so you can later close them.
If you look at the faux OCaml code I provided, I believe the intent
is clear, forgiving OCaml's, ummm, suboptimal syntax. I could code
it up in Java 1.5 (maybe I should, just to make sure it works!) and
since Java doesn't do parameter inference it may all work fine.
> In general, for incremental type building, you need to retain
> the open types.. and it isn't clear if there's any way
> to make it tractable (syntactically I mean).
The code for this in Java 1.5 is quite clear, syntactically. It's a bit
tricky to get it all right, of course, but someone smarter than me already
figured it out, I just want to implement the trick in my language of
choice, which is not Java.
> Unfortunately .. the easiest kind of solution is to write
> a code generator in Python or Perl .. this kind of polymorphism
> is not exactly desirable .. ;(
No, I think you're missing the point of the "exercise" here. I'm not looking for
a code generator, but an OO approach to building extensible visitors with
precise static type checking.
-- Brian
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Caml-list] Polymorphic method question
2006-07-10 23:25 ` brogoff
@ 2006-07-11 2:24 ` skaller
2006-07-11 4:56 ` brogoff
0 siblings, 1 reply; 12+ messages in thread
From: skaller @ 2006-07-11 2:24 UTC (permalink / raw)
To: brogoff; +Cc: Richard Jones, caml-list
On Mon, 2006-07-10 at 16:25 -0700, brogoff wrote:
> The restriction on polymorphism in mutually recursive class
> definitions makes the idea unworkable. Any possibility that restriction will be
> lifted?
I don't believe there is such a restriction: the problem is
when you introduce other types such as variants which must
recurse with class types, there's no support for
type class t1 = ..
and t2 = [`X ..]
etc. The solution, using extra parameters and open
recursion, followed by closure of the recursions,
works but is vastly too messy to encode by hand if there
are more than a couple of parameters needed. This really
does need to be automated in the special case where
you're only opening the types so you can later close them.
In general, for incremental type building, you need to retain
the open types.. and it isn't clear if there's any way
to make it tractable (syntactically I mean).
Unfortunately .. the easiest kind of solution is to write
a code generator in Python or Perl .. this kind of polymorphism
is not exactly desirable .. ;(
Can MetaOcaml can handle this better?
--
John Skaller <skaller at users dot sf dot net>
Felix, successor to C++: http://felix.sf.net
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Caml-list] Polymorphic method question
2006-07-10 19:21 Polymorphic " brogoff
2006-07-10 20:05 ` [Caml-list] " Richard Jones
@ 2006-07-11 2:09 ` Jacques Garrigue
2006-07-11 5:22 ` brogoff
1 sibling, 1 reply; 12+ messages in thread
From: Jacques Garrigue @ 2006-07-11 2:09 UTC (permalink / raw)
To: brogoff; +Cc: caml-list
From: brogoff <brogoff@speakeasy.net>
Subject: [Caml-list] Polymorphic method question
Date: Mon, 10 Jul 2006 12:21:26 -0700 (PDT)
> Hi,
> I'm sure I'll slap my forehead in disgust when someone lifts the
> scales from my eyes, but I'm once again perplexed by a type error
> from OCaml when using objects. Can someone tell me why I get the
> error from the second case (with the classes connected by "and") when
> the first case is OK?
> # class virtual ['a] bar =
> object
> method virtual get : 'a
> end
> and foobar =
> object
> method virtual f : 'a . 'a bar -> 'a
> end;;
> Characters 115-132:
> method virtual f : 'a . 'a bar -> 'a
> ^^^^^^^^^^^^^^^^^
> This type scheme cannot quantify 'a :
> it escapes this scope.
Because bar is not yet completely defined when you use it in foobar.
This is all related with parameter constraint inference: we don't know
yet wether bar's parameter is really polymorphic or is constraint (e.g.
'a = 'b * 'c).
Note that the problem does not occur with direct type definitions, as
constraint inference is not done in that case (this is one of the
reasons you cannot combine type and class definitions.)
# type 'a bar = < get: 'a > and foobar = < f : 'a. 'a bar -> 'a >;;
type 'a bar = < get : 'a >
and foobar = < f : 'a. 'a bar -> 'a >
The only way to solve this problem would be to remove parameter
constraint inference from classes. It would certainly break some
programs, so this seems difficult.
By the way, if you're ready to define your types first, then you
can do this properly.
# class virtual ['a] bar = object method virtual get : 'a end
and virtual foobar = object method virtual f : 'a . 'a bar_t -> 'a end;;
class virtual ['a] bar : object method virtual get : 'a end
and virtual foobar : object method virtual f : 'a bar_t -> 'a end
> BTW, This example was distilled from one in which I could not cleanly
> remove the class recursion, one involving an "extensible visitor" in
> which there is a recursion between the visited and visitor classes.
> Assuming there's an obvious answer to my first question, is there a
> nice workaround in this case?
Extensible visitor is more complex. You can already find the
polymorphic variant solution at
http://www.math.nagoya-u.ac.jp/~garrigue/papers/
There is a new solution using private rows and recursive modules
inside "Private rows: abstracting the unnamed".
With Keiko Nakata, we found another solution using objects in place of
polymorhic variants. This is rather verbose, but here is the code.
This is close to the Odersky&Zenger approach in Scala, but here our
visitor is purely functional.
Note how we are not able to use eval's self directly for recursion, as
we need an abstract row.
Jacques Garrigue
(* OO decomposition in Objective Caml *)
class type ['a,'exp] visit_add = object
method visitNum : int -> 'a
method visitAdd : 'exp -> 'exp -> 'a
end
module type AddTE = sig
type ('a,'exp) t
type exp = < accept : 'a. ('a, exp) t -> 'a >
val num : int -> exp
val add : exp -> exp -> exp
end
module type AddT = sig
include AddTE
val eval : (int, exp) t Lazy.t
end
module AddF(X : AddT with type ('a,'exp) t = private ('a,'exp) #visit_add) =
struct
type ('a, 'exp) t = ('a, 'exp) X.t
class type exp = object ('e) method accept : 'a. ('a, 'e) t -> 'a end
class num x = object (_ : #exp) method accept v = v#visitNum x end
let num x = new num x
class add a b = object (_ : #exp) method accept v = v#visitAdd a b end
let add x = new add x
class eval = object
method visitNum (i : int) = i
method visitAdd (r : exp) (l : exp) =
r#accept (Lazy.force X.eval) + l#accept (Lazy.force X.eval)
end
let eval = lazy (new eval)
end
module rec Add : AddT with type('a,'exp) t = ('a,'exp) visit_add = AddF(Add)
class type ['a,'exp] visit_add_neg = object
inherit ['a,'exp] visit_add
method visitNeg : 'exp -> 'a
end
module type AddNegT = sig
include AddT
val neg : exp -> exp
end
module AddNegF(X : AddNegT with
type ('a,'exp) t = private ('a,'exp) #visit_add_neg) =
struct
module Add = AddF(X)
include (Add : AddTE with type ('a,'e) t = ('a,'e) X.t)
class neg x = object (_ : #Add.exp) method accept v = v#visitNeg x end
let neg x = new neg x
class eval = object
inherit Add.eval
method visitNeg (e : exp) = - e#accept (Lazy.force X.eval)
end
let eval = lazy (new eval)
end
module rec AddNeg : AddNegT with type ('a,'exp) t = ('a,'exp) visit_add_neg =
AddNegF(AddNeg)
# open Add;;
# let e1 = (add (num 2) (num 3));;
val e1 : Add.exp = <obj>
# e1#accept (Lazy.force eval);;
- : int = 5
# open AddNeg;;
# let e2 = neg (e1 : Add.exp :> exp);;
val e2 : AddNeg.exp = <obj>
# e2#accept (Lazy.force eval);;
- : int = -5
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Caml-list] Polymorphic method question
2006-07-10 20:05 ` [Caml-list] " Richard Jones
@ 2006-07-10 23:25 ` brogoff
2006-07-11 2:24 ` skaller
0 siblings, 1 reply; 12+ messages in thread
From: brogoff @ 2006-07-10 23:25 UTC (permalink / raw)
To: Richard Jones; +Cc: caml-list
On Mon, 10 Jul 2006, Richard Jones wrote:
> On Mon, Jul 10, 2006 at 12:21:26PM -0700, brogoff wrote:
> > This type scheme cannot quantify 'a :
> > it escapes this scope.
>
> Check out this thread:
>
> http://caml.inria.fr/pub/ml-archives/caml-list/2005/02/a67b1a509263be01705305f36d64c39c.en.html
>
> Rich.
Hi Rich,
Thanks for the info, I guess I missed that one when it came out. Unfortunately,
the solution proposed, breaking the recursion by introducing some polymorphic
algebraic type to hold any kind of value in some class type to represent the
visitor, breaks the whole thing. There are just too many recursive
dependencies. Here's a more complete, but still small, example. The modules
are only there to show how the classes would go into files, they're not
essential.
PS: Before anyone tells me that algebraic data types are favored for this
over visitor classes, I'm well aware of all that, and in general agree
with those who prefer their ML sans OOP. However, I was trying to encode a
design pattern I read about somewhere (Felleisen?) which made good use of
polymorphic methods, only to find that it just doesn't translate into the OCaml
class system. The restriction on polymorphism in mutually recursive class
definitions makes the idea unworkable. Any possibility that restriction will be
lifted?
(* The following code won't work, but hopefully gives the idea *)
module Shape =
struct
class virtual ['a] shape_visitor =
object
method visit_square : square -> 'a
method visit_rectangle : rectangle -> 'a
method visit_polygon : polygon -> 'a
method visit_translated : translated -> 'a
(* and potentially many more! *)
end
and virtual shape =
object
method virtual visit : 'a . 'a shape_visitor -> 'a
end
and square pt width =
object (self)
inherit shape
method visit visitor = visitor#visit_square self
method as_tuple : ((int * int) * (int * int)) =
let (ll_x, ll_y) = pt in
(pt, (ll_x + width, ll_y + width))
method as_point_list : (int * int) list =
failwith "Shape.square#as_point_list: unimplemented"
end
and rectangle ll ur =
object (self)
inherit shape
method visit visitor = visitor#visit_rectangle self
method as_tuple : ((int * int) * (int * int)) = (ll, ur)
method as_point_list : (int * int) list =
failwith "Shape.rectangle#as_point_list: unimplemented"
end
and polygon points =
object (self)
val points : (int * int) list = points
inherit shape
method visit visitor = visitor#visit_polygon self
method as_point_list : (int * int) list =
points
end
class translated pt s =
object (self)
inherit shape
method visit visitor = visitor#visit_translated self
method get_shape = s
method get_translation = pt
method as_point_list : (int * int) list =
failwith "Shape.translated#as_point_list: unimplemented"
end
end (* module Shape *)
module Contains_point =
struct
(* Writing code that works over shapes *)
class contains_point point =
object
inherit bool Shape.shape_visitor
method make_contains_point p =
new contains_point p
method visit_square : Shape.square node -> bool =
fun s ->
let ((ll_x, ll_y), (ur_x, ur_y)) = s#as_tuple in
let (x, y) = point in
ll_x <= x && x <= ur_x && ll_y <= y && y <= ur_y
method visit_rectangle : Shape.rectangle node -> bool =
fun r ->
let ((ll_x, ll_y), (ur_x, ur_y)) = r#as_tuple in
let (x, y) = point in
ll_x <= x && x <= ur_x && ll_y <= y && y <= ur_y
method visit_polygon : Shape.polygon node -> bool =
fun p ->
failwith "Contains_point.contains_point#visit_polygon: unimplemented"
method visit_translated : Shape.translated node -> bool =
fun t ->
failwith "Contains_point.contains_point#visit_translated: unimplemented"
end;;
--
-- Brian
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Caml-list] Polymorphic method question
2006-07-10 19:21 Polymorphic " brogoff
@ 2006-07-10 20:05 ` Richard Jones
2006-07-10 23:25 ` brogoff
2006-07-11 2:09 ` Jacques Garrigue
1 sibling, 1 reply; 12+ messages in thread
From: Richard Jones @ 2006-07-10 20:05 UTC (permalink / raw)
To: brogoff; +Cc: caml-list
On Mon, Jul 10, 2006 at 12:21:26PM -0700, brogoff wrote:
> This type scheme cannot quantify 'a :
> it escapes this scope.
Check out this thread:
http://caml.inria.fr/pub/ml-archives/caml-list/2005/02/a67b1a509263be01705305f36d64c39c.en.html
Rich.
--
Richard Jones, CTO Merjis Ltd.
Merjis - web marketing and technology - http://merjis.com
Team Notepad - intranets and extranets for business - http://team-notepad.com
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2006-07-12 19:26 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-08-21 21:49 [Caml-list] polymorphic method question nadji
2002-08-21 22:57 ` Jacques Garrigue
2006-07-10 19:21 Polymorphic " brogoff
2006-07-10 20:05 ` [Caml-list] " Richard Jones
2006-07-10 23:25 ` brogoff
2006-07-11 2:24 ` skaller
2006-07-11 4:56 ` brogoff
2006-07-11 2:09 ` Jacques Garrigue
2006-07-11 5:22 ` brogoff
2006-07-11 7:32 ` Jacques Garrigue
2006-07-11 18:20 ` brogoff
2006-07-12 0:37 ` Jacques Garrigue
2006-07-12 19:26 ` brogoff
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox