[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)]}