[clean-list] unique record fields.
Maarten de Mol
maartenm@cs.kun.nl
Tue, 5 Jun 2001 09:54:48 +0200
Hello,
> Hello,
>
> This is probably a very basic question (for which I apologize).
Unfortunately, it is not such a basic question.
> I am trying
> to write hashtables in Clean. The way I want to go about it is to
define
> a Map type (parameterized by key and value types) corresponding to a
record
> containing a (unique) array (and some other useful state):
>
> :: *Map *a b =
> { state :: {[(a, b)]}
> , size :: Int
> , put :: (Map a b) -> a -> b -> (Map a b)
> ... etc.
> }
>
> Then the function to construct an object of this type would look like:
>
> Map hash equal size =
> { state = createArray size [] // <- error 2
> , put = put
> ... etc.
> }
> where
> put :: (*Map *a b) *a b -> (*Map *a b) // <- error 1
> put map key val =
> ...
> map
>
> However when I try to compile this program I get the following type
errors:
>
> Type error [Map.icl,34,put]: "map" attribute at the indicated position
cannot be coerced: Map ^ a b | == b
> Type error [Map.icl,22,Map]: "createArray ({})" cannot create a non-unique
variant of this type at the indicated position: ^ [(a,b)]
>
Error 2: You are in effect constructing an array of unique elements (due to
the '*' in front of a in the type definition of Map).
But if you take a look at the type of createArray you'll see:
createArray :: !Int e -> .(a e)
Because there is no '.' or '*' in front of e, createArray can only
be used
to create arrays of *non-unique* elements.
Solution: I always use array-comprehensions to construct such
arrays:
state = {[] \\ i <- [1..size]}
This will do the trick.
Error 1: There are actually two errors here. The first I won't even try to
explain.
(because I can't) You have to replace the type of 'put' in your
record by:
put :: (Map a b) -> *(a -> *(b -> (Map a b)))
It still is obscure to me why this is needed.
Secondly, you have to change the type of the local function 'put'.
This one is easier: the '*' annotation always has to be written
*outside*
the brackets, not inside. So:
put :: *(Map *a b) *a b -> *Map *a b
(The * inside the brackets will be ignored by the parser and can
be omitted)
As you can see, there are quite some things going on here.
> I am doing nothing in the program except defining the constructor, I am
not
> even calling it. Does anyone have any insight into this?
> If this list is not the right place for these sorts of questions I would
be
> happy to direct them to the right place.
>
> Thanks in advance,
>
> Ilya
>
Maarten de Mol
PS: Note that fields in a unique record will not automatically be unique
themselves.
If you want the state field to be unique, you have to write
state :: *{[(a,b)]}