[mercury-users] Newbie questions about typeclasses
Critterrathman at aol.com
Critterrathman at aol.com
Tue Apr 24 16:05:17 AEST 2001
First, a disclaimer. I've been toying around with polymorphism as understood
in an OOP sense in a number of different languages. I realize that Mercury
isn't geared towards such things, but I use it as a method to learn about
various programming languages. Mercury is definitely unique in what it tries
to do, so I've been trying off and on to learn what I can about the language.
I've been playing around with Mercury for a while, and just haven't quite got
a handle on the syntax of typeclasses (not to mention some of the major
concepts of the language). I don't really know enuf about the language to
frame my questions in a coherent manner, but I figure the only way to learn
is to ask dumb questions. I apologize for not making the questions a bit
more straightforward but hopefully the code is fairly easy to understand (at
least that was the intention). :-)
The code I'm trying to construct is the toy example of shape inheritance
(circle extends shape, etc...). I include what little I've been able to
accomplish at the end of this message (sorry for the long post). A couple of
issues that I've had at this point are:
1). For some reason, MMC complains about not being able to find shape.int3.
I am trying to play with a sort of limited inheritance in this situation
where the circleClass inherits the method signatures of the shapeClass. If I
manually copy the file shape.int2 into the requested file shape.int3,
everything seems to work fine. I don't know enuf about the compiler but a
wild guess would be that each level of inheritance that is split across
modules is adding one to the index of the module file. Of course that's a
WAG. Anyhow, is there a reason why MMC exhibits this behavior?
Here's the calls to MMC for the interface generate:
mmc --make-int shape.m
mmc --make-int circle.m
Here's the error message I get when it tries to create the interface
for circle.m:
--: not found
mercury_compile: can't open file `shape.int3'.
Error reading short interface files.
`circle.int' and `circle.int2' not written.
If I change the calls to the following, I get no complaints:
mmc --make-int shape.m
cp shape.int2 shape.int3
mmc --make-int circle.m
2). I'm not sure how to get the methods for the typeclass to be used. What
I wanted is to just expose the record and the typeclass definitions in the
interface and then map the specific function to the typeclass within the
implementation section of the module. This would mean that the interface
might expose a method called 'getRadius' while the local method can be
implemented locally as 'getRadius_Circle'. If I try to access the method by
the name of the typeclass method, I get an error message about an unsatisfied
constraint.
Here's the call in the main routine that causes the problem:
draw_Circle(setRadius(ACircle, 30))
Here's the error message:
In clause for predicate `polymorph:main/2':
unsatisfiable typeclass constraint(s):
`circle:circleClass((circle:circleRecord))'.
However, if I don't use the typeclass and directly go to the defined
function, it works:
draw_Circle(setRadius_Circle(ACircle, 30))
I think I'm missing something obvious about the way that typeclasses work,
but I thought the purpose was to map method names from local implementation
names into a globally recognized method name. The mapping of the class
method names into the implementation names is taken care of by the instance
declarations. Just wondering what I am missing here?
Along these lines, I really didn't want to put the local implementation mode
into the interface section. If I could get the method names to map off of
the class, I'd probably be able to push the local names into the
implementation section.
3). Also along similar lines, I was having difficulty getting the compiler
to accept pred(draw/3) in the instance declaration. The pred() compiles fine
in the typeclass statement but it complains if I try to map it within the
instance. I see in the documentation that it is allowed to mix predicates
and functions within the instance declarations. The only proviso that I see
is that all the example predicates take a single constraint. In this case,
the pred is doing some simple io so it requires the single argument as well
as the two tag along arguments for input/output. In the code that compiles
and runs, I just commented out the line in the instance declaration:
Here's the line of code that causes the problem:
:- instance shapeClass(circleRecord) where [
pred(draw/3) is draw_Circle,
Here's the error message that I get:
In instance declaration for `shape:shapeClass/1': incorrect
method name(s): predicate `shape:draw/3' .
Anyhow, what exactly am I doing wrong here?
Thanks in advance for any help.
Here's the code as it currently runs.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%% polymorph.m %%%%%%%%%%%%%%%%%%%%%%%%%%%
:- module polymorph.
:- interface.
:- import_module io, int, list, shape, circle.
:- pred main(io__state, io__state).
:- mode main(di, uo) is det.
:- implementation.
main -->
{ Scribble = [circleRecord(10, 20, 5), circleRecord(15, 25, 8)] },
{ ACircle = circleRecord(0, 0, 15) },
drawLoop(Scribble),
draw_Circle(setRadius_Circle(ACircle, 30)).
:- pred drawLoop(list(circleRecord), io__state, io__state).
:- mode drawLoop(in, di, uo) is det.
drawLoop([]) --> [].
drawLoop([Hd | Tl]) -->
draw_Circle(Hd),
draw_Circle(rMoveTo_Circle(Hd, 100, 100)),
drawLoop(Tl).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%% shape.m %%%%%%%%%%%%%%%%%%%%%%%%%%%
:- module shape.
:- interface.
:- import_module io, int.
% declare method interfaces for the shape superclass
:- typeclass shapeClass(This) where [
pred draw(This, io__state, io__state),
func getX(This) = int,
func getY(This) = int,
func setX(This, int) = This,
func setY(This, int) = This,
func moveTo(This, int, int) = This,
func rMoveTo(This, int, int) = This
].
:- implementation.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%% circle.m %%%%%%%%%%%%%%%%%%%%%%%%%%%
:- module circle.
:- interface.
:- import_module io, int, shape.
% declare the constructor for circle class
:- type circleRecord
---> circleRecord(
x :: int,
y :: int,
radius :: int
).
% declare method interfaces for circle subclass
:- typeclass circleClass(This) <= shapeClass(This) where [
func getRadius(This) = int,
func setRadius(This, int) = circleRecord
].
:- pred draw_Circle(circleRecord, io__state, io__state).
:- mode draw_Circle(in, di, uo) is det.
:- func getX_Circle(circleRecord) = int.
:- mode getX_Circle(in) = out is det.
:- func getY_Circle(circleRecord) = int.
:- mode getY_Circle(in) = out is det.
:- func getRadius_Circle(circleRecord) = int.
:- mode getRadius_Circle(in) = out is det.
:- func setX_Circle(circleRecord, int) = circleRecord.
:- mode setX_Circle(in, in) = out is det.
:- func setY_Circle(circleRecord, int) = circleRecord.
:- mode setY_Circle(in, in) = out is det.
:- func setRadius_Circle(circleRecord, int) = circleRecord.
:- mode setRadius_Circle(in, in) = out is det.
:- func moveTo_Circle(circleRecord, int, int) = circleRecord.
:- mode moveTo_Circle(in, in, in) = out is det.
:- func rMoveTo_Circle(circleRecord, int, int) = circleRecord.
:- mode rMoveTo_Circle(in, in, in) = out is det.
:- implementation.
% map the circle methods for shape superclass
:- instance shapeClass(circleRecord) where [
% pred(draw/3) is draw_Circle,
func(getX/1) is getX_Circle,
func(getY/1) is getY_Circle,
func(setX/2) is setX_Circle,
func(setY/2) is setY_Circle,
func(moveTo/3) is moveTo_Circle,
func(rMoveTo/3) is rMoveTo_Circle
].
% map the methods for circle subclass
:- instance circleClass(circleRecord) where [
func(getRadius/1) is getRadius_Circle,
func(setRadius/2) is setRadius_Circle
].
% method definitions for the circle class follow
getX_Circle(This) = This^x.
getY_Circle(This) = This^y.
getRadius_Circle(This) = This^radius.
setX_Circle(circleRecord(_,Y,Radius), X) = circleRecord(X, Y, Radius).
setY_Circle(circleRecord(X,_,Radius), Y) = circleRecord(X, Y, Radius).
setRadius_Circle(circleRecord(X,Y,_), Radius) = circleRecord(X, Y, Radius).
moveTo_Circle(circleRecord(_,_,Radius), X, Y) = circleRecord(X, Y, Radius).
rMoveTo_Circle(circleRecord(X,Y,Radius), DX, DY) = circleRecord(X+DX, Y+DY,
Radius).
draw_Circle(This) -->
io__write_string("Drawing a circle at:("),
io__write_int(getX_Circle(This)),
io__write_string(","),
io__write_int(getY_Circle(This)),
io__write_string("), radius "),
io__write_int(getRadius_Circle(This)),
io__nl.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.mercurylang.org/archives/users/attachments/20010424/49047883/attachment.html>
More information about the users
mailing list