[mercury-users] maintaining state in instances of typeclasses

Fergus Henderson fjh at cs.mu.OZ.AU
Sun May 13 02:36:39 AEST 2001


On 12-May-2001, Terrence Brannon <princepawn at earthlink.net> wrote:
> Hi, I was hoping that someone would complete this program for
> me. Perhaps it is my fault, but after reading the manual, I don't know
> how to create separate instances of typeclasses, each with their own
> state.

>From the code you've written, it looks like you're assuming that Mercury
type classes are similar to classes in Java, C++, etc.
But type classes in Mercury are not the same as classes in OOP languages.
In OOP languages, an instance of a class is an object.
In Mercury, an instance of a type class is a type.
In OOP languages, the class methods get passed the object
as an implicit parameter (`this').
In Mercury, all parameters must be declared and passed explicitly.

> typeclass shape(SHAPE) where [
> 
> func area = float.
> 
> ].

That should be

	typeclass shape(SHAPE) where [

		func area(SHAPE) = float

	].

Note that you need to pass the SHAPE to the area function.

> instance shape(square) where [
> 
> func area = Length * Length.
> 
> ].

To make `square' an instance of the `shape' type class,
you first need to define a `square' type:

	:- type square ---> square(length::int).

Then you can go ahead and make that square type an
instance of the shape type class.  The state information
is obtained from the shape that is passed to the area function:

	:- instance shape(square) where [
	 
	 func area(square(Length)) = Length * Length
	 
	].

It's a little more maintainable if you use the field name
rather than pattern matching:

	:- instance shape(square) where [
	 
	 func area(Square) = Square^length * Square^length

	].

> instance shape(circle) where [
> 
> func area = 3.141 * Radius * Radius.
> 
> ].

	:- import_module math.  % for math__pi

	:- type circle ---> circle(radius::int).

	instance shape(circle) where [
	 
	 func area(circle(Radius)) = math__pi * Radius * Radius
	 
	].

> /*
>  1. enter square's length via STDIN
>  2. enter circle's radius via STDIN

	:- import_module io, require.

	main -->
		print("enter square's length:"), nl,
		read_int(Length),
		{ Square = square(Length) },
		print("enter circle's radius:"), nl,
		read_int(Radius),
		{ Circle = circle(Radius) },
		...

	read_int(Int) -->
		io__read_line_as_string(Res),
		{ Res = ok(S), string__to_int(S, I) ->
			Int = I
		;
			% XXX should improve error handling
			error("invalid input, I/O error, or eof")
		}.

>  3. print area of both, along with the value of each component of the
>  computation. meaning, for squares, print the length and the area.
>  For circles, print the radius and the area.

	main -->
		...
		print(Square^length), nl,
		print(area(Square)), nl,
		print(Circle^length), nl,
		print(area(Circle)), nl,
		...

>  Also, 
>  if a previous area was calculated, print it as well. then store the new area so that it can be
>  printed as the previous area on the next iteration.

To accomplish this, we need to go back and change the definitions
of the square and circle types to store this state.

	:- type square ---> square(length::int, prev_area::maybe(int)).
	:- type circle ---> circle(radius::int, prev_area::maybe(int)).

The lines in main which construct them need to specify that they start
with no previous area:

	main -->
		...
		{ Square = square(Length, no) },
		...
		{ Circle = circle(Radius, no) },

Or alternatively you can leave the original versions of those
two lines in main and instead add functions to construct them:

	square(Length) = square(Length, no).
	circle(Length) = circle(Length, no).

>  4. repeat 1, 2, 3 one time, creating new instances of both circle and square
>  5. print the differences in area between the first and second square
>  6. print the differences in area between the first and second circle

These should be straight-forward.

-- 
Fergus Henderson <fjh at cs.mu.oz.au>  |  "I have always known that the pursuit
                                    |  of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh>  |     -- the last words of T. S. Garp.
--------------------------------------------------------------------------
mercury-users mailing list
post:  mercury-users at cs.mu.oz.au
administrative address: owner-mercury-users at cs.mu.oz.au
unsubscribe: Address: mercury-users-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-users-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the users mailing list